Я немного запутался во всех приятных вещах, которые предлагает laravel с точки зрения контейнера и фасадов МОК. Поскольку я не опытный программист, он учится.
Мне было интересно, в чем разница между этими двумя примерами:
Фасад к «Foo» и зарегистрирован в контейнере через App::bind()
Фасад к «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 () для извлечения значений, которые я только что создал, должен ли я? Поскольку каждый раз, когда используется метод фасада, создается экземпляр нового объекта и как один объект может извлекать свойства другого объекта? Там должно быть три разных экземпляра, но все же я могу получить свойства из этих других экземпляров …