Skip to main content

Wat is de service container

De service container van Laravel is een mechanisme voor het beheren van klasse-afhankelijkheden en het uitvoeren van dependency injection. Dependency injection betekent dat de afhankelijkheden die een klasse nodig heeft via de constructor — of soms via settermethoden — in de klasse worden “geïnjecteerd”. Bekijk het volgende voorbeeld.
In dit voorbeeld moet de PodcastController podcasts ophalen uit een databron zoals Apple Music. Daarom injecteren we een service die podcasts kan ophalen. Door de service te injecteren kun je bij het testen eenvoudig een mock (dummy-implementatie) van de AppleMusic-service inwisselen.
Een goed begrip van de service container is onmisbaar voor het bouwen van grootschalige Laravel-applicaties. Het helpt ook bij het bijdragen aan de Laravel-core zelf.

Zero-configuration resolution

Als een klasse alleen afhankelijk is van andere concrete klassen (dus geen interfaces), hoef je de container niet te vertellen hoe die moet worden opgelost. Stel bijvoorbeeld dat je de volgende code in routes/web.php schrijft.
In dit voorbeeld wordt de klasse in het routebestand gedefinieerd, maar dat is alleen ter demonstratie. In een echte applicatie definieer je serviceklassen in de map app/Services.
Bezoek je deze route, dan lost Laravel de Service-klasse automatisch op en injecteert deze in de routehandler. Je profiteert van dependency injection zonder een configuratiebestand aan te maken. Veel van de klassen die je in een Laravel-applicatie schrijft — controllers, event listeners, middleware — krijgen hun afhankelijkheden automatisch via de container geïnjecteerd.

Bindings

Basisbindings

De meeste bindings registreer je in een service provider. Binnen een service provider heb je via de property $this->app toegang tot de container.

bind

Met de bind-methode registreer je een binding door een klasse- of interfacenaam en een closure door te geven.
De closure ontvangt de container zelf als argument. Hiermee kun je subafhankelijkheden oplossen. Wil je buiten een service provider met de container werken, gebruik dan de App-facade.
Klassen die niet van interfaces afhangen, hoef je niet aan de container te binden. De container kan deze objecten automatisch oplossen via reflectie.

singleton

De singleton-methode bindt een klasse of interface zodat deze slechts één keer wordt opgelost. Eenmaal opgelost geeft de container bij volgende aanroepen dezelfde instantie terug.
Met de methode singletonIf registreer je alleen een singleton-binding als er voor het opgegeven type nog geen binding is geregistreerd.

Het Singleton-attribuut

Je kunt de container ook via het attribuut #[Singleton] op een klasse of interface instrueren om deze slechts één keer op te lossen.

Scoped singletons binden

De scoped-methode bindt een klasse of interface zodat deze slechts één keer wordt opgelost binnen de levenscyclus van een Laravel-request of -job. Deze lijkt op de singleton-methode, maar instanties die met scoped zijn geregistreerd, worden weggegooid telkens wanneer de Laravel-applicatie een nieuwe “levenscyclus” start — bijvoorbeeld wanneer een Laravel Octane-worker een nieuw request verwerkt of een queue worker een nieuwe job verwerkt.
Met de methode scopedIf registreer je alleen een scoped binding als er voor het opgegeven type nog geen binding is geregistreerd.

Het Scoped-attribuut

Je kunt de container ook via het attribuut #[Scoped] op een klasse of interface instrueren om deze slechts één keer per request-/job-levenscyclus op te lossen.

instance

Je kunt ook een bestaande objectinstantie aan de container binden met de instance-methode. Bij volgende aanroepen geeft de container altijd die instantie terug.

Interfaces aan implementaties binden

Een van de krachtigste functies van de service container is het binden van een interface aan een specifieke implementatie. Stel dat je een EventPusher-interface en een RedisEventPusher-implementatie hebt.
Hierdoor injecteert de container RedisEventPusher in klassen die een implementatie van EventPusher nodig hebben. Je hoeft alleen nog de EventPusher-interface te typehinten in de constructor.
Door van interfaces afhankelijk te zijn, hoef je je code niet te wijzigen als je de implementatie vervangt. Dat maakt testen en toekomstige wijzigingen eenvoudiger.

Het Bind-attribuut

Laravel biedt daarnaast het handige Bind-attribuut. Door dit attribuut op een interface te plaatsen, vertel je Laravel welke implementatie automatisch moet worden geïnjecteerd wanneer die interface wordt gevraagd. Bij gebruik van het Bind-attribuut is er geen extra registratie in een service provider nodig. Bovendien kun je meerdere Bind-attributen op een interface plaatsen om per omgeving een andere implementatie te injecteren.
Voor bindings die afhangen van een willekeurige voorwaarde kun je het attribuut BindWhen gebruiken. Aan de closure kan de container worden doorgegeven; de closure geeft true terug wanneer de binding moet worden toegepast. Bind- en BindWhen-attributen worden geëvalueerd in de volgorde waarin ze zijn gedeclareerd.
Voor het BindWhen-attribuut is PHP 8.5 of hoger vereist.
Door daarnaast het Singleton- of Scoped-attribuut te combineren, geef je aan of die containerbinding één keer wordt opgelost of één keer per request/job.

Automatisch oplossen (DI via typehints)

Bij het oplossen van klassen zoals controllers, event listeners en middleware kijkt de service container naar de typehints in de constructor en injecteert de afhankelijkheden automatisch.
Als UserRepository niet van een interface afhangt, is registratie in de container niet nodig. Je hoeft alleen de route te bezoeken en de container lost de afhankelijkheid automatisch op en injecteert deze in de controller.

Oplossen vanuit de container

De make-methode

Met de make-methode los je een klasse-instantie op vanuit de container.
Kunnen niet alle afhankelijkheden van de klasse via de container worden opgelost, dan kun je met de methode makeWith extra argumenten doorgeven.

Automatische injectie

In de praktijk roep je de make-methode zelden rechtstreeks aan. Voeg simpelweg typehints toe aan de constructor van klassen die de container oplost (controllers, event listeners, middleware enz.) en de container injecteert ze automatisch.

De relatie tussen facades en de container

Laravel-facades bieden een statische interface naar objecten in de container. Zo haalt Cache::get() intern de Cache-service uit de container en roept die aan.
Facades zijn een handige wrapper om de container. Bij het testen kun je facades ook vervangen door mocks.

Praktijkvoorbeeld van constructor injection

Laten we een typisch patroon uit een echte applicatie bekijken.
1

De interface definiëren

2

De implementatieklasse maken

3

Binden in een service provider

4

De injectie ontvangen in een controller

Dankzij dit patroon hoef je, als je de betaaldienst van Stripe naar een andere provider omzet, alleen de binding op één plek aan te passen.

Volgende stap

Service providers

Leer hoe je bindings registreert met service providers.
Laatst gewijzigd op 6 september 2026