Contenedor de Servicio
Introducción
El contenedor de servicios de Laravel es una potente herramienta para gestionar las dependencias de clases y realizar la inyección de dependencias. La inyección de dependencias es una frase elegante que esencialmente significa esto: las dependencias de clase se "inyectan" en la clase a través del constructor o, en algunos casos, métodos "setter".
Veamos un ejemplo sencillo:
Un profundo conocimiento del contenedor de servicios de Laravel es esencial para construir una aplicación potente y de gran tamaño, así como para contribuir al propio núcleo de Laravel.
Resolución de Configuración Cero
Si una clase no tiene dependencias o sólo depende de otras clases concretas (no de interfaces), no es necesario indicar al contenedor cómo resolver esa clase. Por ejemplo, puede colocar el siguiente código en su archivo routes/web.php
:
En este ejemplo, al pulsar la ruta /
de tu aplicación se resolverá automáticamente la clase Service
y se inyectará en el manejador de tu ruta. Esto cambia las reglas del juego. Significa que puedes desarrollar tu aplicación y aprovechar las ventajas de la inyección de dependencias sin preocuparte por los archivos de configuración hinchados.
Cuándo Utilizar el Contenedor
Gracias a la resolución de configuración cero, a menudo escribirás dependencias en rutas, controladores, escuchadores de eventos, y en otros lugares sin tener que interactuar manualmente con el contenedor. Por ejemplo, puedes escribir el objeto Illuminate\Http\Request
en tu definición de ruta para poder acceder fácilmente a la petición actual. A pesar de que nunca tenemos que interactuar con el contenedor para escribir este código, es la gestión de la inyección de estas dependencias detrás de las escenas:
Binding
Conceptos Básicos de Binding
Simple Bindings
Dentro de un proveedor de servicios, siempre tienes acceso al contenedor a través de la propiedad $this->app
. Podemos registrar un enlace utilizando el método bind
, pasando el nombre de la clase o interfaz que deseamos registrar junto con un closure que devuelva una instancia de la clase:
Tenga en cuenta que recibimos el propio contenedor como argumento para el resolver. A continuación, podemos utilizar el contenedor para resolver las subdependencias del objeto que estamos construyendo.
Binding A Singleton
El método singleton
vincula una clase o interfaz al contenedor que sólo debe resolverse una vez. Una vez resuelto un enlace singleton, se devolverá la misma instancia de objeto en las siguientes llamadas al contenedor:
Binding Scoped Singletons
Binding Instances
También puede enlazar una instancia de objeto existente en el contenedor utilizando el método instance
. La instancia dada siempre será devuelta en las siguientes llamadas al contenedor:
Binding de Interfaces a Implementaciones
Una característica muy potente del contenedor de servicios es su capacidad para vincular una interfaz a una implementación dada. Por ejemplo, supongamos que tenemos una interfaz EventPusher
y una implementación RedisEventPusher
. Una vez que hemos codificado nuestra implementación RedisEventPusher
de esta interfaz, podemos registrarla con el contenedor de servicios de la siguiente manera:
Esta sentencia indica al contenedor que debe inyectar el RedisEventPusher
cuando una clase necesite una implementación de EventPusher
. Ahora podemos inyectar la interfaz EventPusher
en el constructor de una clase que sea resuelta por el contenedor. Recuerda, controladores, escuchadores de eventos, middleware, y varios otros tipos de clases dentro de las aplicaciones Laravel siempre se resuelven utilizando el contenedor:
Binding contextual
Binding Primitives
A veces puedes tener una clase que recibe algunas clases inyectadas, pero también necesita un valor primitivo inyectado como un entero. Puede utilizar fácilmente la vinculación contextual para inyectar cualquier valor que su clase pueda necesitar:
A veces una clase puede depender de un array de instancias tagged. Usando el método giveTagged
, puedes inyectar fácilmente todos los enlaces del contenedor con esa etiqueta:
Si necesitas inyectar un valor de uno de los ficheros de configuración de tu aplicación, puedes utilizar el método giveConfig
:
Binding de variables tipificadas
Ocasionalmente, puedes tener una clase que recibe un array de objetos tipados usando un argumento variadic del constructor:
Utilizando la vinculación contextual, puede resolver esta dependencia proporcionando al método give
un closure que devuelva un array de instancias de Filter
resueltas:
Para mayor comodidad, también puede proporcionar una matriz de nombres de clase que el contenedor resolverá cada vez que Firewall
necesite instancias de Filter
:
Dependencias de etiquetas variádicas
A veces una clase puede tener una dependencia variada que se indica como una clase determinada (Informe ...$informes
). Utilizando los métodos needs
y giveTagged
, puede inyectar fácilmente todos los enlaces de contenedor con ese tag para la dependencia dada:
Etiquetado
Ocasionalmente, puede que necesites resolver todas las vinculaciones de una determinada "categoría". Por ejemplo, puede que estés construyendo un analizador de informes que reciba un array de diferentes implementaciones de la interfaz Report
. Después de registrar las implementaciones de Report
, puedes asignarles una etiqueta utilizando el método tag
:
Una vez etiquetados los servicios, puedes resolverlos todos fácilmente a través del método tagged
del contenedor:
Extender Bindings
El método extend
permite modificar los servicios resueltos. Por ejemplo, cuando se resuelve un servicio, puedes ejecutar código adicional para decorar o configurar el servicio. El método extend
acepta dos argumentos, la clase de servicio que estás extendiendo y un cierre que debe devolver el servicio modificado. El cierre recibe el servicio que se está resolviendo y la instancia del contenedor:
Resolviendo
El Método make
make
Puedes utilizar el método make
para resolver una instancia de clase desde el contenedor. El método make
acepta el nombre de la clase o interfaz que deseas resolver:
Si algunas de las dependencias de tu clase no se pueden resolver a través del contenedor, puedes inyectarlas pasándolas como un array asociativo al método makeWith
. Por ejemplo, podemos pasar manualmente el argumento del constructor $id
requerido por el servicio Transistor
:
Si desea que la instancia del contenedor Laravel se inyecte en una clase que está siendo resuelta por el contenedor, puede escribir la clase Illuminate\Container\Container
en el constructor de su clase:
Inyección automática
Invocación e inyección de métodos
A veces es posible que desee invocar un método en una instancia de objeto mientras permite que el contenedor inyecte automáticamente las dependencias de ese método. Por ejemplo, dada la siguiente clase
Puede invocar el método generate
a través del contenedor de la siguiente manera:
El método call
acepta cualquier callable de PHP. El método call
del contenedor puede usarse incluso para invocar un cierre mientras se inyectan automáticamente sus dependencias:
Eventos en contenedores
El contenedor de servicios lanza un evento cada vez que resuelve un objeto. Puedes escuchar este evento usando el método resolving
:
PSR-11
Se lanza una excepción si no se puede resolver el identificador dado. La excepción será una instancia de Psr\Container\NotFoundExceptionInterface
si el identificador nunca se vinculó. Si el identificador se vinculó pero no se pudo resolver, se lanzará una instancia de PsrContainerContainerExceptionInterface
.
Última actualización
¿Te fue útil?