hyperf 中可通过监听 exceptioncaught 事件捕获未处理异常并输出堆栈,需注册监听器、确保异常未被默认处理器拦截,并配合 swoole 错误配置实现开发期清晰报错。

Hyperf 中未处理异常默认会由框架内部捕获并返回 HTTP 500 响应,但开发阶段往往需要更清晰地看到原始异常堆栈、触发位置和上下文,以便快速定位问题。要实现对未处理异常的监听与输出,核心是利用 Hyperf 的 事件机制 和 异常处理器扩展能力,而非仅依赖日志配置。
监听未处理异常事件(ExceptionCaught)
Hyperf 提供了 Hyperf\ExceptionHandler\Event\ExceptionCaught 事件,当异常未被 try-catch 捕获且未被全局异常处理器处理时触发。你可以通过监听该事件实现自定义输出(如打印到控制台、写入特定日志文件、上报至监控系统等)。
- 创建监听器类,例如
app/Listener/LogUncaughtExceptionListener.php - 在
listen数组中注册该监听器,对应事件为Hyperf\ExceptionHandler\Event\ExceptionCaught - 在
process()方法中获取$event->getThrowable(),即可访问原始异常对象 - 建议搭配
Hyperf\Utils\Str::trace($e)或$e->getTraceAsString()输出完整堆栈
确保异常未被默认处理器“静默吞掉”
Hyperf 默认的 ExceptionHandler 会捕获大部分异常并返回 JSON 或 HTML 响应,这会导致 ExceptionCaught 事件不触发。若想让未处理异常真正“暴露”,需确认:
- 你的异常未被
ExceptionHandler的isValid()方法匹配(例如自定义异常未继承HttpException或未显式声明支持) - 或临时禁用默认处理器(仅开发环境),在
config/autoload/exceptions.php中注释掉或调整handler配置 - 也可在自定义
ExceptionHandler的handle()中主动抛出异常(不推荐生产环境使用)
配合 Swoole 错误级别与 stderr 输出
对于协程内未捕获的致命错误(如 FatalError、ParseError),Swoole 层可能直接终止协程而不触发 PHP 异常事件。此时可:
- 启用
swoole.display_errors = On(php.ini或启动参数) - 设置
error_reporting(E_ALL)并确保display_errors=On - 在
server.php启动前调用ini_set('log_errors', '1')和ini_set('error_log', 'php://stderr'),确保错误输出到容器/终端标准错误流
验证是否生效的小技巧
写一个故意触发未处理异常的测试路由,例如:
在控制器中写throw new RuntimeException('test uncaught exception');,然后请求该接口,观察终端输出或日志文件是否有对应堆栈。
注意:CLI 命令、定时任务、WebSocket 连接等非 HTTP 场景同样适用上述监听逻辑,只需确保监听器已加载且事件能被派发。











