hyperf di容器本身不依赖协程,但运行在协程环境时,其管理的单例对象默认进程级共享,若服务持有非协程安全状态(如静态变量、未锁共享数组),并发调用将导致数据污染;需通过make()配合协程上下文或连接池实现隔离。

Hyperf 依赖注入容器本身不依赖协程,但运行在协程环境中
Hyperf 的 hyperf/di 容器是一个纯 PHP 实现的 PSR-11 兼容容器,它不强制要求协程 —— 即便你在 CLI 模式下用 php bin/hyperf.php start 之外的方式(比如跑单元测试)调用 $container->get(UserService::class),它照样工作。但真实生产中,它总是在 Swoole 协程上下文里被高频、并发地使用,这就引出了关键约束:容器管理的对象必须是协程安全的。
- 单例对象默认是「进程级」共享的,如果某个服务内部持有非协程安全状态(如静态变量、全局资源句柄、未加锁的共享数组),多个协程同时调用它的方法就可能互相污染
-
@Inject注入的属性或构造函数参数,其对应类的实例化时机发生在协程启动前(如 Worker 启动时)或首次访问时(懒加载),但后续所有协程共用同一个实例 —— 这不是 bug,是设计使然 - 若需「每协程隔离」的依赖(例如每个请求独享一个数据库连接上下文),不能靠容器单例,得用
make()+ 协程上下文存储(如Co::getContext())或工厂注入配合ApplicationContext::getContainer()动态获取
协程生命周期和 DI 容器生命周期错位会出什么问题
常见错误现象:Connection refused 或 MySQL server has gone away 在高并发压测时突然大量出现,但单请求完全正常;或者日志里看到不同用户的 token 在中间件里被混用。
- Swoole Worker 进程常驻,DI 容器在 Worker 启动时初始化,所有单例服务也在此刻创建 —— 它们存活整个 Worker 生命周期,而非单个请求
- 如果你在某个 Service 里手动 new 了一个
PDO并设为 private 属性,又没做连接复用/重连逻辑,那这个连接很可能在某次 MySQL 主动断连后失效,后续所有协程继续用它就会报错 - 更隐蔽的是「闭包绑定」问题:用
Container::set()绑定一个带$this引用的闭包,而该$this所属对象又持有协程局部变量,容易导致内存无法释放或状态错乱
哪些注入方式天然更适合协程场景
不是所有注入方式都平等。在协程密集型服务里,构造函数注入和接口绑定最稳妥;@Inject 注解看似方便,但容易掩盖生命周期问题。
- 构造函数注入:实例化即完成依赖装配,语义清晰,且能配合
__serialize/__unserialize控制序列化行为(对协程跨 tick 场景重要) - 接口绑定(
dependencies.php):把实现类和抽象解耦,方便按环境切换协程安全的实现,比如CacheInterface::class => \Hyperf\Cache\Driver\RedisDriver::class,后者内部已处理协程上下文隔离 - 避免在
@Inject字段上直接写private \Swoole\Coroutine\Channel $channel—— Channel 是协程局部资源,不能跨协程共享,容器不会、也不该帮你做协程感知的懒创建
协程上下文怎么和 DI 配合用才不出事
真要让某个依赖“每协程一份”,别指望容器自动搞定。Hyperf 提供了 ApplicationContext::getContainer()->make(),但它只是新造一个实例,不解决“谁来销毁”问题。正确做法是结合协程结束钩子或中间件生命周期。
- 在
beforeHandle中间件里用Co::getContext()存一个临时服务实例,并在afterHandle清理(注意异常路径也要覆盖) - 对 DB 连接这类资源,优先用 Hyperf 自带的
hyperf/database组件 —— 它的ConnectionPool内部已基于协程 ID 做连接映射,你调$db->select()时自动取当前协程专属连接 - 自定义工厂类里不要返回全局静态对象,而应返回每次调用都新建或从协程上下文取的对象,例如:
return function (ContainerInterface $container) { $cid = Co::getCid(); return $container->get(MyContextualService::class)->forCid($cid); };
dependencies.php 里、看着很无辜的单例绑定 —— 它们一旦持有了非线程/协程安全的状态,就会在高并发下静默崩坏。











