Laravel: Difference App :: bind и приложение :: singleton

Я немного запутался во всех приятных вещах, которые предлагает laravel с точки зрения контейнера и фасадов МОК. Поскольку я не опытный программист, он учится.

Мне было интересно, в чем разница между этими двумя примерами:

  1. Фасад к «Foo» и зарегистрирован в контейнере через App::bind()

  2. Фасад к «Foo» и зарегистрирован в контейнере через App::singleton()

В лучшем понимании Foo::method() будет переписан как $app->make['foo']->method() поэтому в первом примере будут созданы несколько экземпляров класса Foo и во втором примере, поскольку он связан через App::singleton() , тот же экземпляр Foo будет возвращаться каждый раз, когда вызывается метод для этого объекта.

Извините, если ответ на этот вопрос очевиден, но я не могу найти подтверждения по этому вопросу, и нигде это не объяснено.

Это точно так.

Очень простое доказательство – проверить бевахиор. Поскольку приложение Laravel просто расширяет Illuminate\Container\Container , мы будем использовать только контейнер (в моем случае я даже добавлял контейнер как зависимость от моего composer.json) для тестирования.

 require __DIR__ . '/vendor/autoload.php'; class FirstClass { public $value; } class SecondClass { public $value; } // Test bind() $container = new Illuminate\Container\Container(); $container->bind('FirstClass'); $instance = $container->make('FirstClass'); $instance->value = 'test'; $instance2 = $container->make('FirstClass'); $instance2->value = 'test2'; echo "Bind: $instance->value vs. $instance2->value\n"; // Test singleton() $container->singleton('SecondClass'); $instance = $container->make('SecondClass'); $instance->value = 'test'; $instance2 = $container->make('SecondClass'); $instance2->value = 'test2'; // <--- also changes $instance->value echo "Singleton: $instance->value vs. $instance2->value\n"; 

Результат, как и ожидалось:

Bind: test vs. test2

Singleton: test2 vs. test2

Возможно, это грязное доказательство, но на самом деле оно одно.

Вся магия лежит в методе Container::make . Если привязка зарегистрирована как shared (что означает Singleton), экземпляр класса возвращается, в противном случае – новый экземпляр каждый раз.

Источник: https://github.com/laravel/framework/blob/4.2/src/Illuminate/Container/Container.php#L442

BTW, Container::singleton – это то же самое, что и Container::bind с третьим параметром, установленным в true.

Фасады работают как одиночные, даже если базовое связывание не является одиночным.

Допустим, у вас есть:

 $app->bind('foo', 'FooConcrete'); // not a singleton 

а также:

 class Foo extends \Illuminate\Support\Facades\Facade { protected static function getFacadeAccessor() { return 'foo'; } } 

Тогда это создаст 2 экземпляра FooConcrete , как обычно:

 app('foo'); app('foo'); 

Но это создаст только один экземпляр FooConcrete и повторное его использование:

 Foo::someMethod(); Foo::someMethod(); 

Это потому, что resolveFacadeInstance() хранит разрешенные экземпляры.

Однако есть исключение. В большинстве случаев определенный getFacadeAccessor() возвращает строку , как показано выше, но также может возвращать объект . Пример с фасада Schema :

 protected static function getFacadeAccessor() { return static::$app['db']->connection()->getSchemaBuilder(); } 

В таком случае resolveFacadeInstance() не сохраняет экземпляр.

Поэтому, если getFacadeAccessor() возвращает новый экземпляр, каждый вызов в Facade также создает новый экземпляр.

Но где-то я читал, что Ларавель относится к классам, называемым через фасады, всегда, как одинарные?

Таким образом, я столкнулся с этой проблемой:

У меня есть демо-класс, обычно связанный через

  $ this-> app-> bind ('demo', function () {return new Demo ();} 

Устанавливать фасад

  защищенная статическая функция getFacadeAccessor () {return 'demo';  } 

Сам класс выглядит так

  класс Demo 
     {

         private $ value1;        
         private $ value2;        

         public function setVal1 (значение $)
         {
             $ this-> value1 = $ value;
         }

         public function setVal2 (значение $)
         {
             $ this-> value2 = $ value;
         }

         публичная функция getVals ()
         {
             return 'Val 1:'.  $ this-> value1.  «Вал 2:».  $ This-> значение2;
         }   

     } 

Вы сказали мне, что если я буду использовать фасад этого класса, он создаст объект класса, а затем вызовет метод на этом объекте.

Butt Я проверил еще несколько и нашел это очень странное (по крайней мере для меня) поведение:

Если я сделаю

  Demo :: setVal1 ( '13654'); 

а также

  Демо :: setVal2 («случайная строка») 

Я не должен использовать Demo :: getVals () для извлечения значений, которые я только что создал, должен ли я? Поскольку каждый раз, когда используется метод фасада, создается экземпляр нового объекта и как один объект может извлекать свойства другого объекта? Там должно быть три разных экземпляра, но все же я могу получить свойства из этих других экземпляров …