必须配合setinstances([])才真正重置,因forget()仅删除$bindings中绑定定义,不清理$instances中已实例化对象;不清空$instances会导致request/db等对象跨请求残留、内存泄漏。

不能靠 forget() 单独实现,必须配合 setInstances([]) 才算真正重置。ThinkPHP 容器的“重实例化”不是清空绑定就完事——已解析过的对象还留在 $instances 数组里,下次 get() 仍会直接返回旧实例,内存和状态都不会刷新。
为什么 forget() 不等于重新实例化
forget($abstract) 只从 $bindings 数组中删掉绑定定义,不影响已经通过 make() 创建并缓存在 $instances 中的对象。比如你绑定了 'cache' 到 Redis::class,第一次 app('cache') 后,Redis 实例已存进 $instances;再调一次 forget('cache'),下次 app('cache') 依然返回那个旧 Redis 实例,连接、配置、内部状态全没变。
-
forget()是“删注册”,不是“删实例” - 真正控制是否复用实例的是
$instances数组,不是$bindings - 除非显式调用
setInstances([]),否则容器默认走“单例复用”逻辑
pull() 和 make(..., $newInstance = true) 的区别
这两个方法都能绕过 $instances 缓存,但行为不同:
-
pull('cache'):先查$instances,有则返回;没有则make()新建并**不存入**$instances(即每次都是新实例,且不污染缓存) -
make('cache', [], true):强制新建,但新建后**仍会写入**$instances,覆盖原缓存 —— 这反而可能破坏后续正常复用 - 如果你只是临时需要一个干净实例(比如单元测试),用
pull()更安全 - 如果你要全局重置整个容器状态(如 Swoole Worker 生命周期末尾),必须清空
$instances,而不是只调make(..., true)
在 Swoole 长生命周期中安全重置容器
Swoole Worker 复用进程时,容器若不清空 $instances,会导致 Request/Response 对象跨请求残留、数据库连接未释放、缓存实例状态错乱等问题。
- 保留核心绑定(如
'app'、'think\App'、'think\Config'),避免框架崩溃 - 遍历
getBindings(),对非核心项调用forget($abstract) - 关键一步:
$container->setInstances([])—— 这行代码必须有,且要在forget()之后执行 - 如果用了自定义服务提供者(Provider),重置后需手动
register(),或改用request-aware的 lazy binding(例如闭包里用app('request')而非构造注入) - 切勿清空
'app'绑定,否则app('request')会抛出InvalidArgumentException
最易被忽略的点:很多人写了 forget() 就以为搞定了,结果压测时发现内存缓慢上涨、请求间数据串扰——问题几乎都出在漏掉了 setInstances([])。它不是可选项,是长连接场景下容器重置的必要操作。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











