Qué es el service container
El service container de Laravel es el mecanismo para gestionar las dependencias de las clases y realizar la inyección de dependencias. Inyectar dependencias significa «inyectar» en la clase las dependencias que necesita a través del constructor o, en algunos casos, mediante métodos setter. Fíjate en el siguiente ejemplo.PodcastController necesita obtener podcasts desde una fuente de datos como Apple Music. Por eso inyectamos un servicio capaz de obtener podcasts. Al inyectarlo, en las pruebas podemos sustituir con facilidad AppleMusic por un mock (una implementación falsa).
Entender el service container en profundidad es imprescindible para construir aplicaciones Laravel grandes. También ayuda a contribuir al propio núcleo de Laravel.
Resolución sin configuración
Si tu clase solo depende de otras clases concretas (no de interfaces), no necesitas indicarle al container cómo resolverlas. Por ejemplo, imagina que escribes el siguiente código enroutes/web.php.
Este ejemplo define la clase dentro del archivo de rutas con fines de demostración. En una aplicación real, define las clases de servicio en el directorio
app/Services.Service y la inyecta en el handler. No hace falta preparar ningún archivo de configuración para beneficiarse de la inyección de dependencias.
En la mayoría de las clases que escribes en una aplicación Laravel —controladores, listeners de eventos, middlewares, etc.—, las dependencias se inyectan automáticamente a través del container.
Bindings
Bindings básicos
La mayoría de los bindings se registran en los service providers. Dentro de un service provider puedes acceder al container mediante la propiedad$this->app.
bind
Con el métodobind registras un binding pasando el nombre de una clase o interfaz y un closure.
App.
Las clases que no dependen de una interfaz no necesitan registrarse en el container. El container puede resolverlas automáticamente usando reflection.
singleton
El métodosingleton vincula la clase o interfaz de modo que se resuelva una sola vez. Una vez resuelto el singleton, todas las llamadas posteriores al container devuelven la misma instancia.
singletonIf puedes registrar el binding singleton solo si aún no existe uno para el tipo indicado.
Atributo Singleton
Puedes indicarle al container que la clase o interfaz debe resolverse una sola vez añadiendo el atributo#[Singleton].
Bindings de singleton con scope
El métodoscoped vincula la clase o interfaz para que se resuelva una sola vez dentro del ciclo de vida de la petición/job de Laravel. Es similar a singleton, pero las instancias registradas con scoped se descartan cada vez que la aplicación Laravel inicia un nuevo «ciclo de vida», como cuando un worker de Laravel Octane atiende una nueva petición o cuando un worker de cola procesa un nuevo job.
scopedIf puedes registrar el binding con scope solo si aún no existe uno para el tipo indicado.
Atributo Scoped
También puedes indicarle al container que resuelva una sola vez por ciclo de petición/job añadiendo el atributo#[Scoped].
instance
También puedes vincular al container una instancia de objeto ya existente con el métodoinstance. En las llamadas posteriores al container se devolverá siempre esa instancia.
Vincular una interfaz a una implementación
Una de las funcionalidades más potentes del service container es la posibilidad de vincular una interfaz a una implementación concreta. Por ejemplo, imagina que tienes la interfazEventPusher y la implementación RedisEventPusher.
RedisEventPusher en cualquier clase que necesite una implementación de EventPusher. Basta con hacer un type hint de la interfaz EventPusher en el constructor.
Atributo Bind
Laravel también ofrece el útil atributoBind. Añadiéndolo a una interfaz, indicas a Laravel qué implementación inyectar automáticamente cuando se solicita esa interfaz. Con Bind no necesitas registrar nada adicional en un service provider.
Además, colocando varios atributos Bind sobre la interfaz, puedes configurar la inyección de implementaciones distintas por entorno.
BindWhen. Al closure se le puede pasar el container y debe devolver true cuando quieras aplicar el binding. Los atributos Bind y BindWhen se evalúan en el orden en que se declaran.
Para usar el atributo
BindWhen se requiere PHP 8.5 o superior.Resolución automática (DI por type hint)
El service container inyecta automáticamente las dependencias mirando los type hints del constructor al resolver clases como controladores, listeners de eventos o middlewares.UserRepository no depende de una interfaz, no hay que registrarlo en el container. Basta con acceder a la ruta correspondiente y el container resolverá automáticamente la dependencia y la inyectará en el controlador.
Resolver desde el container
Método make
Con el métodomake puedes resolver una instancia de clase desde el container.
makeWith puedes pasar argumentos adicionales.
Inyección automática
En la práctica rara vez llamarás directamente amake. Basta con añadir type hints al constructor de las clases que resuelve el container (controladores, listeners de eventos, middlewares, etc.) y las inyectará automáticamente.
Relación entre fachadas y container
Las fachadas de Laravel ofrecen una interfaz estática a los objetos dentro del container. Por ejemplo,Cache::get() internamente obtiene el servicio Cache desde el container y lo invoca.
Ejemplo práctico de inyección por constructor
Veamos un patrón típico en una aplicación real.1
Define la interfaz
2
Crea la clase de implementación
3
Vincúlala en el service provider
4
Recibe la inyección en el controlador
Stripe a otro proveedor requiere modificar un solo binding.
Próximos pasos
Service providers
Aprende a registrar bindings mediante service providers.