首页 > 解决方案 > Laravel IoC Container - 绑定一个单例,然后在没有原始参数时返回它

问题描述

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

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

在我们的构造Something::classlogger('started')

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

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

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

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

$instance = resolve('blah');

但是日志显示另一个started


这表明容器没有返回与构造执行两次相同的实例。

这可能是因为当我们调用时,resolve我们没有传递与实例化相同的选项。

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

标签: laravelsingletonioc-container

解决方案


您无法同时创建单例和使用参数。以下是来自的相关代码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;
}

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

如果您希望无参数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'.


推荐阅读