You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel DI容器中销毁Scoped实例?问题求助

问题分析与解决方案

你的方法存在明显错误,forgetScopedInstances()的作用和你预期不符,且绑定scoped实例的逻辑违背了Laravel容器的设计意图。

核心问题拆解

  1. forgetScopedInstances()的实际作用
    这个方法仅会清除容器中已解析完成的scoped实例缓存,但不会移除你通过app()->scoped()注册的绑定规则。你当前的绑定是一个始终返回预创建实例的回调函数,即便清除了缓存,下次解析时依然会调用该回调返回同一个旧实例。

  2. 错误的绑定逻辑
    你先手动创建实例,再将其包装为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 14:05:58