Estaba viendo este video y a las 7:10 está agregando una dependencia de db y está usando un cierre para asignar el valor.
Mi pregunta es por qué no usar la asignación directa en su lugar, quiero decir, no está haciendo esto:
$container['db'] = $capsule;
equivalente a hacer esto:
$container['db'] = function ($container) use ($capsule) { return $capsule; }
Si no, ¿cuál es la diferencia y qué forma es mejor?
TLDR es porque la definición de dependencias como cierres hace posible que el contenedor de inyección de dependencia las construya a pedido, por lo tanto, no necesita preocuparse por su orden de definición y administrar sus dependencias manualmente.
Pimple es un contenedor de inyección de dependencia , se supone que lo ayuda a configurar sus objetos administrando sus dependencias de una manera fácil y conveniente.
Si asignas directamente un valor a una clave, Pimple llama a ese valor un parámetro , y cuando necesitas acceder a esa clave, simplemente devuelve ese valor exacto:
$container['sample-param'] = 'foo'; echo $container['sample-param']; //output: foo
Pero el punto es que este parámetro de sample-param
no requiere ninguna configuración, es simplemente un valor y estamos de acuerdo con eso. Pero asuma la siguiente configuración de servicio:
$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();
Preste atención al orden que usé para definir diferentes claves en el contenedor.
myService
necesita cache
, pero la definición de caché viene después de la definición de myService. Y aquí es donde Pimple está ayudando, y es por eso que pasamos contenedores a cada cierre, porque Pimple construirá nuestras dependencias a pedido . Cuando necesitamos acceder a myService
Pimple mira su almacenamiento de datos interno, si previamente creó y almacenó myService
con éxito, devolverá esa misma instancia, de lo contrario, llamará a nuestro cierre para construirlo. Y cuando se llame a nuestro cierre, le pedirá a Pimple ($c es el contenedor de Pimple) que le proporcione sus dependencias (que en este caso es el servicio de cache
). Pimple aplica lo mismo en el caché, si aún no está construido, lo construirá y así sucesivamente... hasta que llegue a la parte que requiere parámetros simples como db-config
que regresará inmediatamente. Y en esta cadena de llamadas de cierre, se construye nuestro objeto y todas sus dependencias.
Ahora imagina lo que sucedería si usáramos valores simples en lugar de cierres. En ese caso, cuando queramos construir myService
, debemos cuidar sus dependencias. Tenemos que asegurarnos de que sus dependencias estén definidas antes de definir el servicio en sí y tenemos que lidiar con otros problemas relacionados con la gestión de dependencias. En ese caso, no podríamos simplemente definir nuestro myService
y asumir que hay un servicio de cache
disponible, que se definirá más adelante.
En ese video, está usando Slim framework para el contenedor que, de manera predeterminada, usa Pimple para su contenedor.
En la documentación de esa página menciona lo siguiente
Definición de servicios Un servicio es un objeto que hace algo como parte de un sistema más grande. Ejemplos de servicios: una conexión de base de datos, un motor de plantillas o un programa de correo. Casi cualquier objeto global puede ser un servicio.
Los servicios se definen mediante funciones anónimas que devuelven una instancia de un objeto:
// define some services $container['session_storage'] = function ($container) { return new SessionStorage('SESSION_ID'); }; $container['session'] = function ($container) { return new Session($container['session_storage']); };
Observe que la función anónima tiene acceso a la instancia del contenedor actual, lo que permite referencias a otros servicios o parámetros.
Por diseño, los contenedores esperan llamar a una función.
Los contenedores de Pimple implementan la interfaz \ArrayAccess
(visto aquí) , y eso significa que pueden hacer que el objeto actúe como una matriz sin ser necesariamente una. En el código fuente notarás offsetSet
y offsetGet
, que es lo que sucede cuando lo haces:
$container['a'] = function($c){ return new Blah();} $thing = $container['a'];
tl; dr Es algo específico del contenedor Pimple, no algo específico de PHP.