Swoole协程中异常需在协程内用try...catch处理,1. 使用throw抛出异常;2. 必须在协程内捕获,否则可能导致崩溃;3. 异常不跨协程传播,需通过Channel传递错误信息;4. 建议封装safeGo函数统一捕获异常,防止服务不稳定。

在Swoole协程中处理异常,和PHP传统的异常机制基本一致,但需注意协程环境的特殊性。你可以使用 try...catch 捕获异常,也可以通过 throw 主动抛出异常。关键是:协程内的异常不会自动跨协程传播,必须在当前协程内捕获。
1. 在协程内抛出异常
使用 throw new Exception() 即可抛出异常。只要在协程函数内部抛出,就可以被同一协程中的 try...catch 捕获。
- 异常必须在协程函数内部抛出和处理
- 不能依赖外层同步代码块捕获协程内部未处理的异常
示例:
go(function () {
try {
throw new RuntimeException('协程内发生错误');
} catch (RuntimeException $e) {
echo '捕获异常: ' . $e->getMessage() . "\n";
}
});
2. 捕获协程内部的异常
如果不在协程内部捕获异常,程序可能会崩溃或静默退出(取决于 Swoole 版本和配置)。因此建议所有可能出错的逻辑都包裹在 try...catch 中。
错误示范(异常未被捕获):
go(function () {
throw new Exception('这个异常没被捕获');
});
// 可能导致进程退出或日志报错
正确做法:
go(function () {
try {
// 可能出错的操作,如协程客户端调用
$client = new Swoole\Coroutine\Http\Client('httpbin.org', 80);
$client->get('/');
if ($client->errCode) {
throw new RuntimeException('HTTP请求失败');
}
} catch (Throwable $throwable) {
// 推荐捕获 Throwable,防止致命错误中断协程
echo '协程内异常: ' . $throwable->getMessage() . "\n";
}
});
3. 跨协程异常传递?不行!
每个协程是独立执行单元,父协程无法直接捕获子协程抛出的异常。你必须通过通信机制(如 Channel)传递错误信息。
使用 Channel 传递异常信息:
$chan = new Swoole\Coroutine\Channel(1);
go(function () use ($chan) {
try {
throw new Exception('模拟出错');
} catch (Exception $e) {
$chan->push(['error' => $e->getMessage()]);
}
});
$result = $chan->pop();
if (isset($result['error'])) {
echo '收到错误: ' . $result['error'] . "\n";
}
4. 建议:统一捕获避免崩溃
为防止协程因未捕获异常导致服务不稳定,可以封装一个安全的 go 函数:
function safeGo(callable $func) {
go(function () use ($func) {
try {
$func();
} catch (Throwable $throwable) {
echo "协程异常未处理: {$throwable->getMessage()}\n";
// 可记录日志或上报监控
}
});
}
// 使用
safeGo(function () {
throw new Exception('出错了');
});
基本上就这些。Swoole协程里抛异常很简单,关键是要在协程自己内部处理好,别让它“裸奔”。










