$container->make() 每次新建实例,不参与单例管理,生命周期由php引用计数决定,协程切换不触发销毁;持有外部资源时须显式释放,如close()或defer清理。

Hyperf 3.0 中通过 $container->make() 在协程内动态创建对象,其生命周期与协程上下文和容器管理策略强相关,并非简单的“随协程结束而销毁”。关键在于区分对象本身生命周期、依赖注入方式,以及是否涉及资源释放。
make 创建的对象默认是短生命周期
make() 每次调用都会新建一个实例,不参与容器单例管理。即使类已注册为单例,make() 仍会绕过单例缓存,返回全新对象。这意味着:
- 该对象本身不会被容器自动回收或复用
- 它的存在周期由 PHP 变量引用决定:一旦无变量持有,PHP GC 会在合适时机回收
- 若对象实现了
__destruct()或实现了__invoke等可释放逻辑,需自行确保调用时机
协程环境不影响 make 对象的内存生命周期
协程切换(如 await、go、co)不会自动触发 make 出的对象销毁。协程只是执行上下文的调度单位,不接管对象生命周期管理:
- 在协程 A 中
make(UserService::class),协程挂起后该对象只要仍有引用(比如被闭包捕获、赋值给类属性、存入数组),就继续存活 - 协程 B 启动时无法访问协程 A 的
make实例,除非显式传递或共享到全局/静态作用域 - 不要依赖“协程结束 = 对象自动释放”——这容易引发内存泄漏或状态残留
需要手动管理资源释放的场景
当 make 的对象持有外部资源(如数据库连接、文件句柄、长连接客户端),且未使用容器托管的单例组件时,必须主动释放:
- 推荐在对象内部实现
__destruct(),但注意:PHP GC 不保证立即执行,尤其在协程密集场景下可能延迟 - 更可靠的方式是显式调用关闭方法,例如:
$client->close()或$resource->destroy() - 可在协程退出前用
defer注册清理逻辑(Hyperf 3.0+ 支持):defer(fn() => $client?->close());
与 inject + lazy 的本质区别
@Inject(lazy=true) 注入的是代理对象,首次调用方法时才 make 并缓存;而直接 make() 是即时、无缓存、无代理的原始实例化:
- 前者适合需要延迟初始化且希望复用的依赖(如耗时构造的 RPC 客户端)
- 后者适合一次性的、带运行时参数的场景(如
make(Validator::class, ['rules' => $rules])) - 两者都不受协程生命周期自动约束,但
lazy代理对象一旦创建,后续复用的就是同一个实例(即转为单例行为)











