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

Laravel IoC Container - Binding a singleton then returning it when you don't have the original params

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

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

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

然后我们通过控制器中的容器制作class,例如

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

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

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

$instance = resolve('blah');

但是日志显示另一个 started


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

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

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

无法同时创建单例和使用参数。这是来自 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' 的默认实例。