Hyperf-事件机制+异常处理
Hyperf-事件机制+异常处理
标签(空格分隔): php, hyperf
异常处理器
在 Hyperf 里,业务代码都运行在 Worker 进程 上,也就意味着一旦任意一个请求的业务存在没有捕获处理的异常的话,都会导致对应的 Worker 进程 被中断退出,这对服务而言也是不能接受的,捕获异常并输出合理的报错内容给客户端也是更加友好的。
我们可以通过对各个 server 定义不同的 异常处理器(ExceptionHandler),一旦业务流程存在没有捕获的异常,都会被传递到已注册的 异常处理器(ExceptionHandler) 去处理。
异常记录到日志
// 日志类
<?php
declare(strict_types=1);
namespace App\Utils;
class NativeLog
{
private $dirPath;
public function __construct()
{
$this->dirPath = BASE_PATH . '/runtime/logs/' . date("Ymd") . '/';
if (!is_dir($this->dirPath)) {
mkdir($this->dirPath, 0777, true);
}
}
public function error(string $data) : bool
{
$data = "[ ERROR ] [" . date("Y-m-d H:i:s") . "] " . $data . PHP_EOL;
file_put_contents($this->dirPath . "error.log", $data, FILE_APPEND);
return true;
}
}
hyperf 本身就实现了异常类的接管,如果有异常会打印到控制台输出。

// 增加异常信息的记录日志
/**
* 记录文本异常日志
* @param Throwable $throwable
*/
public function writeLog(Throwable $throwable)
{
$AppExceptionLog['server'] = "http";
$AppExceptionLog['method'] = $this->request->getMethod();
$AppExceptionLog['path'] = $this->request->url();
$AppExceptionLog['params'] = $this->request->all();
$AppExceptionLog['file'] = $throwable->getFile();
$AppExceptionLog['line'] = $throwable->getLine();
$AppExceptionLog['message'] = $throwable->getMessage();
(new NativeLog())->error(json_encode($AppExceptionLog));
}
日志记录效果

但是有个问题,try catch 捕获的代码如果有异常就不会记录
引入事件机制
事件模式是一种经过了充分测试的可靠机制,是一种非常适用于解耦的机制,分别存在以下 3 种角色:
事件(Event) 是传递于应用代码与 监听器(Listener) 之间的通讯对象
监听器(Listener) 是用于监听 事件(Event) 的发生的监听对象
事件调度器(EventDispatcher) 是用于触发 事件(Event) 和管理 监听器(Listener) 与 事件(Event) 之间的关系的管理者对象
用通俗易懂的例子来说明就是,假设我们存在一个 UserService::register() 方法用于注册一个账号,在账号注册成功后我们可以通过事件调度器触发 UserRegistered 事件,由监听器监听该事件的发生,在触发时进行某些操作,比如发送用户注册成功短信,在业务发展的同时我们可能会希望在用户注册成功之后做更多的事情,比如发送用户注册成功的邮件等待,此时我们就可以通过再增加一个监听器监听 UserRegistered 事件即可,无需在 UserService::register() 方法内部增加与之无关的代码。
代码示例
// 新增异常事件
<?php
declare(strict_types=1);
namespace App\Event;
/**
* 系统异常事件
* Class AppException
* @package App\Event
*/
class AppException
{
public $throwable;
public function __construct($throwable)
{
$this->throwable = $throwable;
}
}
// 新增异常事件监听器
<?php
declare(strict_types=1);
namespace App\Listener;
use App\Event\AppException;
use App\Utils\NativeLog;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\HttpServer\Contract\RequestInterface;
/**
* 异常事件监听器
* Class AppExceptionListener
* @package App\Listener
* @Listener()
*/
class AppExceptionListener implements ListenerInterface
{
/**
* @Inject()
* @var RequestInterface
*/
private $request;
/**
* @Inject()
* @var NativeLog
*/
private $nativeLog;
/**
* @inheritDoc
*/
public function listen(): array
{
// TODO: Implement listen() method.
// 返回一个该监听器要监听的事件数组,可以同时监听多个事件
return [
AppException::class,
];
}
/**
* @param object $throwable
*/
public function process(object $throwable)
{
$throwable = $throwable->throwable;
$request = $this->request;
$AppExceptionLog['server'] = "http";
$AppExceptionLog['method'] = $request->getMethod();
$AppExceptionLog['path'] = $request->url();
$AppExceptionLog['params'] = $request->all();
$AppExceptionLog['file'] = $throwable->getFile();
$AppExceptionLog['line'] = $throwable->getLine();
$AppExceptionLog['message'] = $throwable->getMessage();
$this->nativeLog->error(json_encode($AppExceptionLog));
}
}
// 控制器
<?php
declare(strict_types=1);
namespace App\Admin\Controller;
use App\Admin\Model\UserModel;
use App\Admin\Service\UserService;
use App\Event\AppException;
use App\Rpc\Inter\UserServiceInter;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\AutoController;
use Hyperf\Utils\Context;
use Psr\EventDispatcher\EventDispatcherInterface;
use function _HumbugBoxa5be08ba8ddb\React\Promise\Stream\first;
/**
* 用户控制器
* Class UserController
* @package App\Admin\Controller
* @AutoController()
*/
class UserController extends AdminBaseController
{
/**
* @Inject
* @var EventDispatcherInterface
*/
private $eventDispatcher;
/**
* 异常测试
*/
public function exception()
{
try {
array_column();
} catch (\Throwable $throwable) {
$this->eventDispatcher->dispatch(new AppException($throwable));
}
}
Hyperf-事件机制+异常处理的更多相关文章
- 【移动端兼容问题研究】javascript事件机制详解(涉及移动兼容)
前言 这篇博客有点长,如果你是高手请您读一读,能对其中的一些误点提出来,以免我误人子弟,并且帮助我提高 如果你是javascript菜鸟,建议您好好读一读,真的理解下来会有不一样的收获 在下才疏学浅, ...
- tkinter事件机制
一.tkinter.Event tkinter的事件机制跟js是一样的,也是只有一个Event类,这个类包罗万象,集成了键盘事件,鼠标事件,包含各种参数. 不像java swing那种强类型事件,sw ...
- [解惑]JavaScript事件机制
群里童鞋问到关于事件传播的一个问题:“事件捕获的时候,阻止冒泡,事件到达目标之后,还会冒泡吗?”. 初学 JS 的童鞋经常会有诸多疑问,我在很多 QQ 群也混了好几年了,耳濡目染也也收获了不少,以后会 ...
- Atitit 数据库的事件机制--触发器与定时任务attilax总结
Atitit 数据库的事件机制--触发器与定时任务attilax总结 1.1. 事件机制的图谱1 2. 触发器的类型2 3. 实现原理 After触发器 Vs Instead Of触发器2 3.1. ...
- 深入浅出iOS事件机制
原文地址: http://zhoon.github.io/ios/2015/04/12/ios-event.html 本文章将讲解有关iOS事件的传递机制,如有错误或者不同的见解,欢迎留言指出. iO ...
- Java 事件机制
java事件机制包括三个部分:事件.事件监听器.事件源. 1.事件.一般继承自java.util.EventObject类,封装了事件源对象及跟事件相关的信息,用于listener的相应的方法之中,作 ...
- Angular $scope和$rootScope事件机制之$emit、$broadcast和$on
Angular按照发布/订阅模式设计了其事件系统,使用时需要“发布”事件,并在适当的位置“订阅”或“退订”事件,就像邮箱里面大量的订阅邮件一样,当我们不需要时就可以将其退订了.具体到开发中,对应着$s ...
- JavaScript 详说事件机制之冒泡、捕获、传播、委托
DOM事件流(event flow )存在三个阶段:事件捕获阶段.处于目标阶段.事件冒泡阶段. 事件捕获(event capturing):通俗的理解就是,当鼠标点击或者触发dom事件时,浏览器会 ...
- DOM事件机制进一步理解
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...
随机推荐
- dedecms织梦后台栏目显示文档数不为0,但点进去之后什么都没有
曾经通过sql语句直接删除过dede_addonarticle或者dede_archives或者dede_arctiny中的记录,这三个表是有关联的,如果要通过sql语句删除内容,一定要同时将这三个表 ...
- 数据结构-kmp算法
定义 改进字符串的匹配算法 关键:通过实现一个包含了模式串的局部匹配信息的next()函数,利用匹配失败的信息,减少匹配次数. 1.BF算法 暴力匹配 给定 文本串S "BBC ABCDAB ...
- hdu 6703 array(权值线段树)
Problem Description You are given an array a1,a2,...,an(∀i∈[1,n],1≤ai≤n). Initially, each element of ...
- poj 2007 凸包构造和极角排序输出(模板题)
Scrambled Polygon Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 10841 Accepted: 508 ...
- hdu5233 Gunner II
Problem Description Long long ago, there was a gunner whose name is Jack. He likes to go hunting ver ...
- Educational DP Contest F - LCS (LCS输出路径)
题意:有两个字符串,求他们的最长公共子序列并输出. 题解:首先跑个LCS记录一下dp数组,然后根据dp数组来反着还原路径,只有当两个位置的字符相同时才输出. 代码: char s[N],t[N]; i ...
- Codeforces Round #649 (Div. 2) B. Most socially-distanced subsequence (数学,差分)
题意:有一长度为\(n\)的数组,求一子序列,要求子序列中两两差的绝对值最大,并且子序列尽可能短. 题解:将数组看成坐标轴上的点,其实就是求每个单调区间的端点,用差分数组来判断单调性. 代码: #in ...
- XV6学习(14)Lab fs: File system
代码在github上. 这次实验是要对文件系统修改,使其支持更大的文件以及符号链接,实验本身并不是很复杂.但文件系统可以说是XV6中最复杂的部分,整个文件系统包括了七层:文件描述符,路径名,目录,in ...
- TextCNN代码实践
在上文<TextCNN论文解读>中已经介绍了TextCNN的原理,本文通过tf2.0来做代码实践. 数据集:来自中文任务基准测评的数据集IFLYTEK 导库 import os impor ...
- Win10永久禁用驱动程序强制签名
在win10下用一个命令就可以禁用驱动程序强制签名 1.禁止强制签名,以管理员的身份运行cmd 执行以下命令 bcdedit.exe /set nointegritychecks on 恢复默认验证, ...