必须使用 coroutine::getcontext() 存储协程私有数据,因为 swoole 常驻内存,静态变量、全局数组等会跨协程污染;context 自动绑定生命周期,安全隔离且无需手动清理。

直接用 Coroutine::getContext() 存协程私有数据,是 Swoole 4.5+ 的标准做法,安全、轻量、无需手动维护协程 ID 映射。它不是“可选技巧”,而是高并发下避免数据污染的必要手段。
为什么必须用 Context 而不是静态变量或全局数组
因为 Swoole 是常驻内存模型,所有协程共享同一份 PHP 进程空间。如果在 onRequest 里写:
-
static $user_id = null;→ 多个请求协程会互相覆盖 -
global $trace_id;→ 协程 A 写入后挂起,协程 B 改写,A 恢复时读到的是 B 的值 -
$GLOBALS['ctx']或对象属性 → 同样跨协程可见,完全不可靠
这类写法在线上极易引发 trace_id 串号、用户身份错乱、资源未释放等隐蔽故障。
正确使用 Coroutine::getContext() 的方式
调用 Co::getContext() 返回当前协程专属的 Coroutine\Context 实例,它自动绑定协程生命周期:
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 只在协程内调用才有效(如
onRequest、go回调中),Worker 启动阶段调用返回null -
$ctx = Co::getContext(); $ctx->set('user_id', 123);→ 数据仅本协程可读 -
$ctx->get('user_id')→ 只能取到本协程 set 的值,其他协程即使 key 相同也查不到 - 协程结束时,该 Context 自动销毁,无需手动清理
常见误用与避坑点
这些错误看似细微,但在线上高频请求下必然出问题:
- 在非协程环境(比如
onWorkerStart)调用Co::getContext()→ 返回null,后续 set/get 全部失败 - 以为
$a = Co::getContext(); $b = Co::getContext();是两个不同对象 → 实际是同一个实例,重复调用无开销 - 试图用 Context 跨 Worker 进程传数据 → Context 仅限单 Worker 内,跨进程请用
Swoole\Table或 Redis - 传入无效协程 ID 做跨协程读取:
Co::getContext($cid)中 $cid 必须存在且未退出,否则返回空
一个简洁可靠的使用示例
在 HTTP 请求中注入 trace_id 并透传:
$server->on('request', function ($request, $response) {
$ctx = Co::getContext();
$trace_id = $request->header['x-trace-id'] ?? uniqid('req_', true);
$ctx->set('trace_id', $trace_id);
// 后续任意位置(包括嵌套协程)都能安全读取
go(function () use ($ctx) {
\Swoole\Coroutine::sleep(0.1);
echo "当前 trace_id: " . $ctx->get('trace_id') . "\n";
});
$response->end("OK");
});
每个请求拥有独立 trace_id,不会交叉污染,也不用担心协程调度导致的数据错位。










