Cos’è il service container
Il service container di Laravel è il meccanismo che gestisce le dipendenze delle classi ed esegue la dependency injection. Per “dependency injection” si intende “iniettare” nella classe le sue dipendenze attraverso il costruttore o, in alcuni casi, un setter. Vediamo un esempio.PodcastController deve recuperare un podcast da una fonte dati come Apple Music. Iniettiamo quindi il servizio che sa recuperarlo. Grazie all’injection, in test possiamo sostituire facilmente AppleMusic con un mock (implementazione fittizia).
Capire a fondo il service container è indispensabile per costruire grandi applicazioni Laravel. Ti aiuta anche a contribuire al core di Laravel stesso.
Risoluzione zero-configuration
Se una classe dipende solo da altre classi concrete (non interfacce), non devi dire al container come risolverla. Ad esempio, questo codice inroutes/web.php:
L’esempio definisce la classe direttamente nel file di route a scopo dimostrativo. In un’applicazione reale, le classi di servizio vanno nella directory
app/Services.Service e lo inietta nell’handler della route. Beneficerai della dependency injection senza scrivere alcuna configurazione.
Nella maggior parte delle classi di un’app Laravel — controller, event listener, middleware ecc. — le dipendenze vengono iniettate automaticamente dal container.
Binding
Binding di base
La maggior parte dei binding si registra all’interno dei service provider. Nel provider puoi accedere al container tramite$this->app.
bind
Conbind registri un binding passando un nome di classe o interfaccia e una closure.
App.
Le classi che non dipendono da interfacce non hanno bisogno di essere bindate. Il container le risolve automaticamente tramite reflection.
singleton
Il metodosingleton registra un binding che verrà risolto una sola volta. Una volta risolto, tutte le chiamate successive restituiranno la stessa istanza.
singletonIf registri il binding singleton solo se il tipo non è già bindato.
Attributo Singleton
Puoi indicare al container di risolvere una sola volta anche applicando l’attributo#[Singleton] alla classe o interfaccia.
Binding scoped
Conscoped bindi una classe o interfaccia a un’istanza risolta una sola volta all’interno del ciclo di vita di una richiesta / job. Simile a singleton, ma le istanze registrate con scoped vengono scartate ogni volta che l’applicazione avvia un nuovo “ciclo di vita” — ad esempio quando un worker di Laravel Octane processa una nuova richiesta o un queue worker elabora un nuovo job.
scopedIf registri il binding scoped solo se non è già registrato.
Attributo Scoped
Puoi ottenere lo stesso comportamento applicando l’attributo#[Scoped] alla classe o interfaccia.
instance
Puoi bindare un’istanza già esistente coninstance. Tutte le chiamate successive restituiscono quella stessa istanza.
Bindare un’interfaccia a un’implementazione
Una delle potenzialità del service container è la possibilità di bindare un’interfaccia a un’implementazione specifica. Ad esempio, dati l’interfacciaEventPusher e la sua implementazione RedisEventPusher:
RedisEventPusher in tutte le classi che dipendono da EventPusher. Basta usare il type hint dell’interfaccia nel costruttore.
Attributo Bind
Laravel offre anche il pratico attributoBind. Applicandolo all’interfaccia, dici a Laravel quale implementazione iniettare automaticamente quando quell’interfaccia viene richiesta. Con Bind non serve registrare il binding nel service provider.
Puoi mettere più Bind sulla stessa interfaccia per iniettare implementazioni diverse a seconda dell’ambiente.
BindWhen. La closure riceve il container e restituisce true quando il binding va applicato. Bind e BindWhen sono valutati nell’ordine di dichiarazione.
Per usare
BindWhen serve PHP 8.5 o superiore.Risoluzione automatica (DI tramite type hint)
Nella risoluzione di classi come controller, event listener e middleware, il service container guarda i type hint del costruttore e inietta automaticamente le dipendenze.UserRepository non dipende da un’interfaccia, non serve registrarla nel container: basta accedere a una route che usi il controller e il container risolve e inietta le dipendenze.
Risolvere dal container
Metodo make
Conmake risolvi un’istanza dal container.
makeWith.
Injection automatica
In pratica, quasi non chiamerai maimake direttamente. Basta aggiungere i type hint al costruttore delle classi che il container risolve (controller, event listener, middleware ecc.) e il container inietterà automaticamente le dipendenze.
Facade e container
Le facade di Laravel sono un’interfaccia statica agli oggetti del container. Ad esempio,Cache::get() recupera internamente il servizio Cache dal container e ne chiama il metodo.
Esempio pratico di constructor injection
Vediamo un pattern tipico in un’applicazione reale.1
Definisci l'interfaccia
2
Crea la classe di implementazione
3
Registra il binding nel service provider
4
Ricevi l'injection nel controller
Stripe a un altro provider di pagamento, basta cambiare il binding in un unico punto.
Prossimi passi
Service provider
Come registrare i binding usando i service provider.