Skip to main content

Was ist der Service-Container

Der Service-Container von Laravel ist ein Mechanismus zur Verwaltung von Klassenabhängigkeiten und zur Durchführung von Dependency Injection. Dependency Injection bedeutet, dass die von einer Klasse benötigten Abhängigkeiten über den Konstruktor oder gegebenenfalls über Setter-Methoden in die Klasse „injiziert” werden. Sehen Sie sich das folgende Beispiel an:
In diesem Beispiel muss der PodcastController einen Podcast von einer Datenquelle wie Apple Music beziehen. Dazu wird ein Dienst injiziert, der Podcasts abrufen kann. Durch das Injizieren des Dienstes lässt sich beim Testen ein Mock (eine Dummy-Implementierung) des AppleMusic-Dienstes leicht einsetzen.
Ein tiefes Verständnis des Service-Containers ist beim Aufbau großer Laravel-Anwendungen unerlässlich. Es hilft auch dabei, zum Laravel-Core selbst beizutragen.

Zero-Configuration-Auflösung

Wenn eine Klasse nur von anderen konkreten Klassen (keinen Interfaces) abhängt, müssen Sie dem Container nicht mitteilen, wie sie aufzulösen ist. Nehmen Sie zum Beispiel folgenden Code in routes/web.php an:
In diesem Beispiel wird die Klasse innerhalb der Routendatei definiert – dies dient nur zu Demonstrationszwecken. In einer echten Anwendung sollten Service-Klassen im Verzeichnis app/Services definiert werden.
Beim Aufruf dieser Route löst Laravel die Service-Klasse automatisch auf und injiziert sie in den Route-Handler. Sie profitieren also von Dependency Injection, ohne eine Konfigurationsdatei anlegen zu müssen. Bei vielen Klassen, die Sie in einer Laravel-Anwendung schreiben – etwa Controller, Event-Listener oder Middleware – werden Abhängigkeiten automatisch über den Container injiziert.

Bindings

Einfache Bindings

Die meisten Bindings werden innerhalb von Service-Providern registriert. In einem Service-Provider können Sie über die Eigenschaft $this->app auf den Container zugreifen.

bind

Mit der bind-Methode registrieren Sie ein Binding, indem Sie einen Klassen- oder Interface-Namen zusammen mit einer Closure übergeben:
Die Closure erhält als Argument den Container selbst und kann darüber Unterabhängigkeiten auflösen. Wenn Sie den Container außerhalb eines Service-Providers verwenden möchten, nutzen Sie die App-Fassade:
Klassen, die nicht von einem Interface abhängen, müssen nicht an den Container gebunden werden. Der Container kann solche Objekte automatisch über Reflection auflösen.

singleton

Die singleton-Methode bindet eine Klasse oder ein Interface so, dass sie nur ein einziges Mal aufgelöst wird. Ist ein Singleton einmal aufgelöst, gibt der Container bei jedem weiteren Aufruf dieselbe Instanz zurück.
Mit der singletonIf-Methode registrieren Sie ein Singleton-Binding nur dann, wenn für den angegebenen Typ noch kein Binding registriert wurde.

Singleton-Attribut

Alternativ können Sie eine Klasse oder ein Interface mit dem Attribut #[Singleton] versehen, um dem Container mitzuteilen, dass sie nur ein einziges Mal aufgelöst werden soll.

Scoped Singletons binden

Die scoped-Methode bindet eine Klasse oder ein Interface so, dass sie innerhalb eines Laravel-Request-/Job-Lebenszyklus nur ein einziges Mal aufgelöst wird. Sie ähnelt der singleton-Methode, allerdings werden mit scoped registrierte Instanzen jedes Mal verworfen, wenn die Laravel-Anwendung einen neuen „Lebenszyklus” beginnt – etwa wenn ein Laravel Octane-Worker einen neuen Request verarbeitet oder ein Queue-Worker einen neuen Job bearbeitet.
Mit der scopedIf-Methode registrieren Sie ein Scoped-Binding nur dann, wenn für den angegebenen Typ noch kein Binding registriert wurde.

Scoped-Attribut

Alternativ können Sie eine Klasse oder ein Interface mit dem Attribut #[Scoped] versehen, um dem Container mitzuteilen, dass sie innerhalb eines Request-/Job-Lebenszyklus nur ein einziges Mal aufgelöst werden soll.

instance

Eine bereits existierende Objektinstanz können Sie über die instance-Methode an den Container binden. Bei nachfolgenden Aufrufen des Containers wird stets diese Instanz zurückgegeben.

Interfaces an Implementierungen binden

Eine der leistungsstärksten Funktionen des Service-Containers ist die Möglichkeit, ein Interface an eine bestimmte Implementierung zu binden. Angenommen, es existiert das Interface EventPusher und die Implementierung RedisEventPusher:
Dadurch injiziert der Container in jede Klasse, die eine Implementierung von EventPusher benötigt, den RedisEventPusher. Sie müssen dann lediglich das Interface EventPusher als Type-Hint im Konstruktor angeben:
Wenn Sie von Interfaces abhängen, müssen Sie Ihren Code nicht anpassen, wenn Sie die Implementierung austauschen. Das erleichtert das Testen und spätere Änderungen erheblich.

Bind-Attribut

Laravel bietet außerdem das praktische Bind-Attribut. Indem Sie ein Interface mit diesem Attribut versehen, teilen Sie Laravel mit, welche Implementierung automatisch injiziert werden soll, wenn dieses Interface angefordert wird. Bei Verwendung des Bind-Attributs ist keine zusätzliche Registrierung in einem Service-Provider erforderlich. Darüber hinaus können Sie mehrere Bind-Attribute auf einem Interface platzieren, um je nach Umgebung unterschiedliche Implementierungen injizieren zu lassen.
Für Bindings, die von einer beliebigen Bedingung abhängen, können Sie das BindWhen-Attribut verwenden. Der Closure kann der Container übergeben werden, und sie gibt true zurück, wenn das Binding angewendet werden soll. Die Attribute Bind und BindWhen werden in der Reihenfolge ihrer Deklaration ausgewertet.
Das BindWhen-Attribut erfordert PHP 8.5 oder höher.
In Kombination mit dem Singleton- oder Scoped-Attribut können Sie außerdem festlegen, ob das Container-Binding nur ein einziges Mal oder einmal pro Request/Job aufgelöst werden soll.

Kontextuelle Bindings

Manchmal möchten Sie zwei Klassen, die dasselbe Interface verwenden, jeweils unterschiedliche Implementierungen injizieren. Nehmen Sie etwa an, zwei Controller hängen von unterschiedlichen Implementierungen des Contracts Illuminate\Contracts\Filesystem\Filesystem ab. Laravel stellt für die Definition dieses Verhaltens eine einfache, fluent Schnittstelle bereit.
An when() können Sie eine Klasse oder ein Array von Klassen übergeben. Mit needs() geben Sie das Zielinterface an, mit give() die Closure, die zur Auflösung verwendet wird. Auf diese Weise können Sie – auch wenn dasselbe Filesystem-Interface per Type-Hint angegeben ist – pro Controller unterschiedliche Disks injizieren.

Kontextuelle Attribute

Da kontextuelle Bindings häufig verwendet werden, um Treiber- oder Konfigurationsimplementierungen zu injizieren, stellt Laravel verschiedene Kontext-Attribute bereit, damit Sie kontextuelle Bindings nicht manuell in einem Service-Provider definieren müssen. Zum Beispiel können Sie mit dem Storage-Attribut eine bestimmte Storage-Disk injizieren.
Neben dem Storage-Attribut bietet Laravel die Attribute Auth, Cache, Config, Context, DB, Give, Log, RequestAttribute, RouteParameter und Tag.
Das Attribut RouteParameter löst den Routenparameter auf, dessen Name mit dem Namen der Eigenschaft übereinstimmt. Bei Bedarf können Sie den Namen des Routenparameters auch explizit angeben, etwa #[RouteParameter('photo')]. Das Attribut RequestAttribute löst Eingabewerte der aktuellen Request-Instanz auf. Möchten Sie einen Schlüssel referenzieren, der vom Eigenschaftsnamen abweicht, geben Sie ihn explizit an, z. B. #[RequestAttribute('user_organization')].
Das Attribut Give verwenden Sie, wenn Sie beim Auflösen eines Interfaces zu einer konkreten Klasse anstelle der gewöhnlichen automatischen Auflösung per Type-Hint eine bestimmte Implementierung angeben möchten.

Automatische Auflösung (DI per Type-Hint)

Wenn der Service-Container Klassen wie Controller, Event-Listener oder Middleware auflöst, berücksichtigt er die Type-Hints des Konstruktors und injiziert die Abhängigkeiten automatisch.
Solange UserRepository nicht von einem Interface abhängt, ist keine Registrierung im Container notwendig. Sobald die entsprechende Route aufgerufen wird, löst der Container die Abhängigkeit automatisch auf und injiziert sie in den Controller.

Auflösen aus dem Container

Methode make

Mit der make-Methode können Sie eine Klasseninstanz aus dem Container auflösen:
Falls Abhängigkeiten der Klasse nicht vom Container aufgelöst werden können, lassen sich über die Methode makeWith zusätzliche Argumente übergeben:

Automatische Injection

In der Praxis rufen Sie die make-Methode selten direkt auf. Bei Klassen, die vom Container aufgelöst werden – etwa Controller, Event-Listener oder Middleware – reicht es aus, Type-Hints im Konstruktor anzugeben; der Container übernimmt die Injection dann automatisch.

Fassaden und der Container

Die Fassaden von Laravel bieten eine statische Schnittstelle zu Objekten im Container. So ruft beispielsweise Cache::get() intern den Cache-Dienst aus dem Container ab und delegiert den Aufruf an ihn.
Fassaden sind komfortable Wrapper um den Container. Beim Testen lassen sie sich außerdem durch Mocks ersetzen.

Konstruktor-Injection – ein praktisches Beispiel

Betrachten wir ein typisches Muster aus einer realen Anwendung.
1

Interface definieren

2

Implementierung erstellen

3

Im Service-Provider binden

4

Injection im Controller entgegennehmen

Mit diesem Muster genügt es, das Binding an einer einzigen Stelle zu ändern, wenn Sie den Zahlungsdienst zum Beispiel von Stripe auf einen anderen Anbieter umstellen möchten.

Nächste Schritte

Service-Provider

Erfahren Sie, wie Sie mit Service-Providern Bindings registrieren.
Zuletzt geändert am 11. September 2026