Laravel IoC容器-绑定单例,然后在没有原始参数时将其返回

时间:2019-05-24 07:40:28

标签: laravel singleton ioc-container

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

$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时,我们没有传递与实例化相同的选项。

如果是这样,我们如何解决这个问题而不在某处设置静态变量?

1 个答案:

答案 0 :(得分:0)

无法创建一个单例并同时使用参数。以下是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为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'的默认实例。