【问题标题】:Laravel IoC Container - Binding a singleton then returning it when you don't have the original paramsLaravel IoC Container - 绑定一个单例,然后在没有原始参数时返回它
【发布时间】:2019-10-10 18:42:12
【问题描述】:

我们正在尝试注册一个单例,例如

$this->app->singleton('blah', function ($app, $options) {
    return $app->makeWith(Something::class, $options);
});

在Something::class 的构造中我们logger('started')

然后我们通过控制器中的容器创建类,例如

$something = app()->makeWith('blah', ['x' => 'y'])

我们查看日志,可以看到started

然后我们尝试在其他地方将其拉出容器,例如

$instance = resolve('blah');

但是日志显示另一个started


这表明容器没有返回相同的实例,因为构造被执行了两次。

这可能是因为当我们调用 resolve 时,我们传入的选项与实例化它的选项不同。

如果是这样,我们如何在不设置静态变量的情况下解决这个问题?

【问题讨论】:

    标签: laravel singleton ioc-container


    【解决方案1】:

    您无法同时创建单例和使用参数。这是来自Container.php的相关代码:

    // If an instance of the type is currently being managed as a singleton we'll
    // just return an existing instance instead of instantiating new instances
    // so the developer can keep using the same objects instance every time.
        if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
            return $this->instances[$abstract];
        }
    

    然后

    // If the requested type is registered as a singleton we'll want to cache off
    // the instances in "memory" so we can return it later without creating an
    // entirely new instance of an object on each subsequent request for it.
    if ($this->isShared($abstract) && ! $needsContextualBuild) {
       $this->instances[$abstract] = $object;
    }
    
    

    请注意,如果实例是使用 makeWith 和参数创建的(除了具有上下文绑定时),$needsContextualBuild 为真。

    如果您希望无参数 resolve 始终解析最后解析的实例,您可以执行以下操作:

    //Bind or singleton doesn't matter now
    $this->app->bind('blah', function ($app, $options) { 
        return $app->makeWith(Something::class, $options);
    });
    $this->app->afterResolving('blah', function ($resolvedObject) {
         $this->app->instance('blah', $resolvedObject);
    });
    
    $this->app->makeWith('blah', [ 'a' => 'b' ]); //New object 1
    $this->app->make('blah'); //Reused object 1
    $this->app->makeWith('blah', [ 'a' => 'b' ]); //New object 2
    $this->app->make('blah'); //Reused object 2
    

    请注意,用不同的上下文解析相同的别名仍然会解析一个新对象并将该对象绑定为'blah' 的默认实例。

    【讨论】:

    • 谢谢你,我看看能不能把它换成你的 afterResolving 技术,一旦我开始这个项目就会报告:) 谢谢
    猜你喜欢
    • 2017-05-25
    • 2018-11-15
    • 2014-11-22
    • 1970-01-01
    • 2018-08-11
    • 1970-01-01
    • 1970-01-01
    • 2021-03-12
    • 1970-01-01
    相关资源
    最近更新 更多