Hyperf 必须在 Swoole 协程环境(如 php bin/hyperf.php start)中运行,非协程下调用协程 API 会触发无法捕获的 Fatal error;应使用 Coroutine::inCoroutine() 判断环境,正确启动服务或命令,并可扩展异常处理器增强可观测性。

Hyperf 默认在 Swoole CLI 模式(如 php bin/hyperf.php start)下运行,此时协程环境已就绪,异常可被正确捕获与格式化。若你尝试在非协程上下文(如命令行同步模式、测试脚本、或未启动 Swoole 的环境下)直接调用协程相关代码(如 co::sleep()、Coroutine::create()、或使用 Channel、Redis::pool() 等需协程支持的组件),会抛出类似:
这类错误并非“协程异常信息未显示”,而是 PHP 致命错误(Fatal error),无法被 try/catch 捕获,自然也不会走 Hyperf 的异常处理器。
确认当前是否处于协程环境
在关键逻辑前加入判断,避免在非协程中误用协程 API:
- 使用
Co::pid() !== -1或Coroutine::id() > 0判断是否已在协程中 - Hyperf 提供了辅助方法:
Hyperf\Utils\Coroutine::inCoroutine()(推荐) - 示例:
use Hyperf\Utils\Coroutine;<br>if (! Coroutine::inCoroutine()) {<br> throw new RuntimeException('This operation requires coroutine environment.');<br>}<br>// 此处可安全调用 co::sleep(1);
修改运行模式以启用协程环境
Hyperf 应用必须运行在 Swoole 启动的协程服务器中,才能支持协程功能。常见错误运行方式及修正:
- ❌ 错误:直接执行
php index.php或php bin/hyperf.php(无start子命令)→ 不启动 Swoole,无协程 - ✅ 正确:使用
php bin/hyperf.php start启动 HTTP 服务,或php bin/hyperf.php server:start - ✅ 命令行任务:通过
php bin/hyperf.php your:command执行命令时,Hyperf 会自动创建一个协程上下文(v2.2+ 默认启用),但需确保命令类中不提前退出协程环境 - ✅ 单元测试:若需测试协程逻辑,请使用
Hyperf\TestUtils\TestCase并在setUp中手动启动协程环境(如go(function () { ... });),或使用@beforeClass启动 Swoole 测试服
自定义协程异常处理器(增强可观测性)
Hyperf 默认使用 Hyperf\ExceptionHandler\ExceptionHandler 处理未捕获异常。对于协程内抛出的异常(如 Redis 连接超时、Channel 关闭后写入等),它能正常捕获并记录。若需更详细的协程上下文信息,可扩展异常处理器:
- 重写
ExceptionHandler::handle(),在日志中补充Coroutine::id()、Coroutine::stats()或当前协程堆栈(debug_backtrace()) - 监听
Swoole\Event::on('workerError')(需在ServerProcess中注册),捕获 worker 进程内未处理的协程致命错误(较少见,但可用于兜底) - 开启 Swoole 日志:
swoole.log_level = 5(DEBUG),配合swoole.log_file查看底层协程调度日志
调试技巧:快速验证协程可用性
在任意控制器或命令中插入以下代码,立即验证环境是否就绪:
go(function () {<br> \Hyperf\Support\Functions\info('I am in coroutine #' . \Swoole\Coroutine::id());<br> \co::sleep(0.1);<br> \Hyperf\Support\Functions\info('Coroutine sleep done.');<br>});<br>return 'Check logs for coroutine output.';
若看到两条 info 日志 → 协程正常;若报 Must be called in the coroutine environment → 当前不在协程中,需检查运行命令或入口方式。


















