如何在Laravel DI容器中销毁Scoped实例?问题求助
问题分析与解决方案
你的方法存在明显错误,forgetScopedInstances()的作用和你预期不符,且绑定scoped实例的逻辑违背了Laravel容器的设计意图。
核心问题拆解
forgetScopedInstances()的实际作用
这个方法仅会清除容器中已解析完成的scoped实例缓存,但不会移除你通过app()->scoped()注册的绑定规则。你当前的绑定是一个始终返回预创建实例的回调函数,即便清除了缓存,下次解析时依然会调用该回调返回同一个旧实例。错误的绑定逻辑
你先手动创建实例,再将其包装为scoped绑定的回调,这完全偏离了scoped绑定的设计目的——scoped是让容器在当前作用域内动态创建实例,而非预先创建好实例后重复返回。
正确实现方式
如果需要支持动态传入参数并能重置实例,可调整如下:
方式一:动态创建实例+移除绑定实现重置
修改testResolveClass函数,让容器动态创建实例,并在需要重置时移除旧绑定:
use Illuminate\Foundation\Application; it('should be able to remove scoped instances', function () { class TestClass { public function __construct( public int $count, ) { } } function testResolveClass($class, array $args = []): object { // 如果已存在绑定,先移除(实现重置) if (app()->bound($class)) { app()->forgetBinding($class); } // 注册scoped绑定,动态创建实例 app()->scoped($class, fn (Application $app) => $app->make($class, $args)); return app($class); } // 创建第一个实例 $instance = testResolveClass(TestClass::class, ['count' => 123]); $id = spl_object_id($instance); // 执行重置:移除绑定 app()->forgetBinding(TestClass::class); // 创建新实例 $instance = testResolveClass(TestClass::class, ['count' => 456]); $id2 = spl_object_id($instance); // 验证结果 expect() ->and($id2)->not->toBe($id) ->and($instance->count)->toBe(456); });
方式二:手动管理实例状态(按需选择)
如果需要更精细的控制,也可以直接通过以下方法管理:
- 检查是否存在绑定:
app()->bound(TestClass::class) - 检查是否已解析实例:
app()->resolved(TestClass::class) - 移除绑定并清除实例:
app()->forgetBinding(TestClass::class)
总结
你遇到的问题根源是错误的绑定方式,forgetScopedInstances()无法移除你注册的绑定回调,只能清除已解析的缓存实例。调整绑定逻辑让容器动态创建实例,再配合forgetBinding()就能实现重置实例的需求。
内容的提问来源于stack exchange,提问作者michiruf
相关产品推荐
相关产品推荐

