Контейнер Laravel IoC - связывание синглтона и его возврат, если у вас нет исходных параметров - PullRequest
2 голосов
/ 24 мая 2019

Мы пытаемся зарегистрировать синглтон, например.

$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 голосов
/ 24 мая 2019

Нет способа создать синглтон и использовать параметры одновременно.Вот соответствующий код из 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 имеет значение true, если экземпляр создан с использованием makeWith и параметров (в дополнение кимеющий контекстную привязку).

Если вы хотите, чтобы 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'.

...