Zum Hauptinhalt springen

Was ist ein Contract?

Die „Contracts” von Laravel sind ein Satz von Interfaces, die die Kernservices des Frameworks definieren. So beschreibt zum Beispiel der Contract Illuminate\Contracts\Queue\Queue die Methoden, die zum Einreihen von Jobs benötigt werden, und Illuminate\Contracts\Mail\Mailer die Methoden zum Versenden von E-Mails. Für jeden Contract existiert eine entsprechende Implementierung im Framework. Laravel bringt beispielsweise Queue-Implementierungen für verschiedene Treiber sowie einen Mailer auf Basis des Symfony Mailers mit. Alle Laravel-Contracts liegen in einem eigenen GitHub-Repository. Dieses dient als Schnellreferenz für alle verfügbaren Contracts und stellt ein einzelnes, entkoppeltes Paket dar, das Sie bei der Entwicklung von Paketen für die Zusammenarbeit mit Laravel-Services verwenden können.
Ein Contract ist nichts anderes als ein Interface. Er funktioniert exakt wie ein normales PHP-Interface. Laravel liefert die Implementierung dazu und injiziert sie über den Service Container.

Unterschied zwischen Contract und Facade

Facades und Helferfunktionen bieten einen bequemen Zugriff auf Laravel-Services, ohne dass Sie Contracts aus dem Service Container per Type-Hint auflösen müssen. In den meisten Fällen gibt es zu jeder Facade einen passenden Contract. Die wichtigsten Unterschiede zwischen Facades und Contracts:
AspektFacadeContract
Deklaration der AbhängigkeitNicht nötig (überall aufrufbar)Explizit im Konstruktor
TestenMit shouldReceive() mockenMit üblichen Mocking-Bibliotheken ersetzen
Typischer EinsatzEinfache Nutzung innerhalb der AnwendungPaketentwicklung, explizites Abhängigkeitsmanagement
LesbarkeitEin Import genügtAbhängigkeiten sofort im Konstruktor sichtbar
Facades müssen im Konstruktor nicht angefordert werden, während Contracts als explizite Abhängigkeit im Konstruktor definiert werden können. Manche Entwicklerinnen und Entwickler bevorzugen dieses explizite Definieren von Abhängigkeiten und setzen daher auf Contracts. Andere schätzen den Komfort der Facades. Für die meisten Anwendungen sind Facades in der Entwicklung problemlos ausreichend.

Wann sollten Sie Contracts einsetzen?

Ob Contract oder Facade – das ist eine Frage des persönlichen Stils bzw. der Teamvorlieben. Beide Ansätze ermöglichen robuste, testbare Laravel-Anwendungen. Contracts und Facades schließen sich nicht aus. Sie können in einem Teil der Anwendung Facades verwenden und in einem anderen auf Contracts setzen. Besonders sinnvoll sind Contracts in folgenden Fällen:
  • Wenn Sie ein Paket entwickeln, das mit mehreren PHP-Frameworks zusammenarbeitet – über das Paket illuminate/contracts können Sie die Interaktion mit Laravel-Services definieren, ohne in Ihrer composer.json konkrete Laravel-Implementierungen zu fordern.
  • Wenn Sie Abhängigkeiten explizit machen möchten – anhand des Konstruktors ist auf einen Blick ersichtlich, wovon eine Klasse abhängt.
  • Wenn Sie Implementierungen austauschen möchten – der Wechsel zu einer anderen Implementierung über den Service Container gelingt so besonders einfach.

Verwendung von Contracts

Wie bekommen Sie eine Contract-Implementierung? Ganz einfach. Viele Klassenarten in Laravel – Controller, Event Listener, Middleware, Queue-Jobs, Route-Closures – werden über den Service Container aufgelöst. Um eine Contract-Implementierung zu erhalten, geben Sie das Interface einfach als Type-Hint im Konstruktor der jeweiligen Klasse an. Sehen Sie sich zum Beispiel den folgenden Event Listener an.
<?php

namespace App\Listeners;

use App\Events\OrderWasPlaced;
use App\Models\User;
use Illuminate\Contracts\Redis\Factory;

class CacheOrderInformation
{
    /**
     * Erstelle den Event Listener.
     */
    public function __construct(
        protected Factory $redis,
    ) {}

    /**
     * Verarbeite das Event.
     */
    public function handle(OrderWasPlaced $event): void
    {
        // ...
    }
}
Wird der Event Listener aufgelöst, liest der Service Container die Type-Hints des Konstruktors aus und injiziert passende Werte.

Eigene Contracts erstellen

Mit eigenen Contracts können Sie die Abhängigkeiten zwischen den Bestandteilen Ihrer Anwendung klar herausarbeiten.
1

Interface definieren

Legen Sie im Verzeichnis app/Contracts ein Interface an.
<?php

namespace App\Contracts;

interface PaymentGateway
{
    /**
     * Den angegebenen Betrag belasten.
     */
    public function charge(int $amount, string $token): bool;

    /**
     * Eine Zahlung erstatten.
     */
    public function refund(string $transactionId): bool;
}
2

Implementierungsklasse erstellen

Erstellen Sie eine Klasse, die den Contract implementiert.
<?php

namespace App\Services;

use App\Contracts\PaymentGateway;

class StripePaymentGateway implements PaymentGateway
{
    public function charge(int $amount, string $token): bool
    {
        // Zahlungsabwicklung über die Stripe-API ...
        return true;
    }

    public function refund(string $transactionId): bool
    {
        // Erstattung über die Stripe-API ...
        return true;
    }
}
3

Im Service Provider binden

Verknüpfen Sie Contract und Implementierung in einem Service Provider.
use App\Contracts\PaymentGateway;
use App\Services\StripePaymentGateway;

$this->app->singleton(PaymentGateway::class, StripePaymentGateway::class);
4

Per Type-Hint injizieren lassen

Geben Sie den Contract im Konstruktor eines Controllers oder einer anderen Klasse als Type-Hint an.
<?php

namespace App\Http\Controllers;

use App\Contracts\PaymentGateway;
use Illuminate\Http\Request;

class OrderController extends Controller
{
    public function __construct(
        protected PaymentGateway $payment,
    ) {}

    public function store(Request $request)
    {
        $this->payment->charge(
            $request->amount,
            $request->payment_token
        );

        // ...
    }
}
Wollen Sie den Zahlungsdienstleister später von Stripe auf einen anderen Anbieter umstellen, genügt eine Anpassung an einer einzigen Stelle – der Bindung. Die Controller-Logik bleibt unverändert.

Übersicht wichtiger Contracts

Ausschnitt einer Zuordnung häufig genutzter Contracts zu ihren Facades:
ContractFacade
Illuminate\Contracts\Auth\Access\GateGate
Illuminate\Contracts\Auth\FactoryAuth
Illuminate\Contracts\Bus\DispatcherBus
Illuminate\Contracts\Cache\FactoryCache
Illuminate\Contracts\Cache\RepositoryCache::driver()
Illuminate\Contracts\Config\RepositoryConfig
Illuminate\Contracts\Console\KernelArtisan
Illuminate\Contracts\Container\ContainerApp
Illuminate\Contracts\Encryption\EncrypterCrypt
Illuminate\Contracts\Events\DispatcherEvent
Illuminate\Contracts\Filesystem\FactoryStorage
Illuminate\Contracts\Filesystem\FilesystemStorage::disk()
Illuminate\Contracts\Hashing\HasherHash
Illuminate\Contracts\Mail\MailerMail
Illuminate\Contracts\Notifications\DispatcherNotification
Illuminate\Contracts\Queue\FactoryQueue
Illuminate\Contracts\Queue\QueueQueue::connection()
Illuminate\Contracts\Queue\ShouldQueue
Illuminate\Contracts\Redis\FactoryRedis
Illuminate\Contracts\Routing\ResponseFactoryResponse
Illuminate\Contracts\Routing\UrlGeneratorURL
Illuminate\Contracts\Session\SessionSession::driver()
Illuminate\Contracts\Translation\TranslatorLang
Illuminate\Contracts\Validation\FactoryValidator
Illuminate\Contracts\View\FactoryView
Eine vollständige Übersicht aller Contracts finden Sie im Repository illuminate/contracts.

Nächste Schritte

Facades

Vertiefen Sie die Funktionsweise von Facades und wie Sie sie testen.
Zuletzt geändert am 13. Juli 2026