я смотрел это видео а в 7:10 он добавляет зависимость db и использует замыкание для присвоения значения.
Мой вопрос: почему бы просто не использовать прямое назначение, я имею в виду, не делает это:
$container['db'] = $capsule;
эквивалентно делать это:
$container['db'] = function ($container) use ($capsule) {
return $capsule;
}
Если нет, то какая разница и какой путь лучше?
TLDR это потому, что определение зависимостей как замыканий позволяет контейнеру внедрения зависимостей создавать их по требованию, поэтому вам не нужно беспокоиться об их порядке определения и управлении их зависимостями вручную.
Прыщ Контейнер для инъекций зависимостей, он должен помочь вам настроить ваши объекты, управляя их зависимостями простым и удобным способом.
Если вы непосредственно назначаете значение ключу, Pimple вызывает это значение параметр, и когда вам нужно получить доступ к этому ключу, он просто возвращает это точное значение:
$container['sample-param'] = 'foo';
echo $container['sample-param'];
//output: foo
Но дело в том, что это sample-param
не требует никакой настройки, это просто значение, и мы в порядке с этим. Но допустим следующую настройку сервиса:
$container['myService'] = function($c) {
$service = new \Some\Complicated\Service();
//this service depends on cache service
$service->setCache($c['cache']);
return $service;
}
$container['cache'] = function($c) {
$cache = new \Cache\Driver();
//our cache driver needs a db connection
$cache->setDbConnection($c['db']);
return $cache;
}
$container['db'] = function($c) {
//our database connection requires some parameters
$dbConnection = new \Database\Connection($c['db-config']);
return $dbConnection;
}
$container['db-config'] = [
'username' => 'foo',
'password' => 'bar',
'host' => 'localhost'
];
//Now we want to user our service:
$container['myService']->doSomething();
Обратите внимание на порядок, который я использовал для определения разных ключей в контейнере.
myService
потребности cache
но определение кэша идет после определения myService. И здесь Pimple помогает, и именно поэтому мы передаем контейнер каждому закрытию, потому что Pimple собирается построить наши зависимости по требованию. Когда нам нужно получить доступ myService
Pimple смотрит на свое внутреннее хранилище данных, если оно ранее построено и сохранено myService
успешно, он вернет тот же экземпляр, иначе он вызовет наше закрытие, чтобы построить его. И когда наше закрытие вызывается, оно попросит Pimple ($ c — контейнер Pimple) дать ему dependecies (который в этом случае является cache
оказание услуг). Pimple применяет то же самое к кешу, если он еще не создан, он будет его строить и так далее … пока не доберется до части, которая требует простых параметров, таких как db-config
который немедленно вернется. И в этой цепочке вызовов замыканий наш объект и все его зависимости построены.
Теперь представьте, что произойдет, если мы используем простые значения вместо замыканий? В том случае, когда мы хотим построить myService
мы должны заботиться о своих зависимостях. Мы должны убедиться, что его зависимости определены до мы определяем сам сервис и мы приходится иметь дело с другими проблемами, связанными с управлением зависимостями. В этом случае мы не могли бы просто определить наш myService
а также предполагать Eсть cache
услуга доступна, которая будет определена позже.
В этом видео он использует Slim Framework для контейнера, который по умолчанию использует Pimple для своего контейнера.
В документации на этой странице упоминается следующее
Определение сервисов Сервис — это объект, который делает что-то как часть
большей системы. Примеры услуг: подключение к базе данных,
шаблонизатор или почтовик. Почти любой глобальный объект может быть
оказание услуг.Сервисы определяются анонимными функциями, которые возвращают экземпляр
объект:// define some services $container['session_storage'] = function ($container) { return new SessionStorage('SESSION_ID'); }; $container['session'] = function ($container) { return new Session($container['session_storage']); };
Обратите внимание, что анонимная функция имеет доступ к текущему экземпляру контейнера, разрешая ссылки на другие службы или параметры.
По своей конструкции контейнеры ожидают вызова функции
Контейнеры прыща реализуют \ArrayAccess
интерфейс (видно здесь), и это означает, что они могут заставить объект действовать как массив, не обязательно будучи единым целым. В исходном коде вы заметите offsetSet
а также offsetGet
, что происходит, когда вы делаете:
$container['a'] = function($c){ return new Blah();}
$thing = $container['a'];
ТЛ; др Это особенность контейнера Pimple, а не PHP.
Это абсолютно другое. Первый $container['db'] = $capsule;
значит что $container
массив имеет db
ключ и этот ключ равен $capsule
,
второй означает, что у вас есть $container
массив и db
Ключ имеет значение закрытия. Вы можете увидеть разницу при выводе двух результатов:
Пример закрытия:
$capsule = 1;
$container['db'] = function ($container) use ($capsule) {
return $capsule;
};
var_dump($container);
Результат:
Array(1) {
["db"]=>
object(Closure)#1 (2) {
["static"]=>
array(1) {
["capsule"]=>
int(1)
}
["parameter"]=>
array(1) {
["$container"]=>
string(10) "<required>"}
}
}
Не закрывающийся пример:
$capsule = 1;
$container['db'] = $capsule;
var_dump($container);
Результат:
result array(1) {
["db"]=>
int(1)
}
Вы можете прочитать о замыканиях в руководстве по PHP для лучшего понимания их роли. Руководство по закрытию PHP