Was ist eine Facade?
Facades stellen eine „statische” Schnittstelle zu Klassen bereit, die im Service Container Ihrer Anwendung verfügbar sind. Laravel bringt zahlreiche Facades mit, über die Sie fast alle Funktionen des Frameworks erreichen. Laravel-Facades fungieren als „statische Proxies” auf konkrete Klassen im Service Container. Dabei bieten sie eine kompakte, ausdrucksstarke Syntax bei gleichzeitig besserer Testbarkeit und Flexibilität als klassische statische Methoden. Alle Laravel-Facades sind im NamespaceIlluminate\Support\Facades definiert.
Sie müssen nicht sofort jedes Detail hinter Facades verstehen. Beginnen Sie einfach mit der Nutzung und lernen Sie Laravel Schritt für Schritt kennen.
Wie Facades funktionieren
In einer Laravel-Anwendung sind Facades Klassen, die einen Zugriff auf ein Objekt aus dem Container bereitstellen. Realisiert wird das über die KlasseFacade. Alle Laravel-Facades sowie eigene Facades erben von der Basisklasse Illuminate\Support\Facades\Facade.
Die Basisklasse Facade nutzt die Magic Method __callStatic(), um Aufrufe an der Facade an das aus dem Container aufgelöste Objekt zu delegieren.
Cache. Diese leitet den Zugriff an eine Implementierung von Illuminate\Contracts\Cache\Factory weiter. Alle Aufrufe über die Facade landen bei der internen Cache-Instanz von Laravel.
Wenn Sie sich die Klasse Illuminate\Support\Facades\Cache ansehen, werden Sie keine statische Methode get finden:
Cache-Facade erbt von der Basis Facade und definiert die Methode getFacadeAccessor(). Deren Rückgabewert ist der Name der Bindung im Service Container. Wenn ein Nutzer eine statische Methode der Cache-Facade aufruft, löst Laravel die Bindung cache aus dem Service Container auf und ruft auf dem Objekt die gewünschte Methode (hier get) auf.
Wann Facades sinnvoll sind – und wann nicht
Vorteile
Facades bieten viele Vorteile. Sie stellen eine prägnante, gut merkbare Syntax für Laravel-Funktionalität bereit, ohne dass Sie sich lange Klassennamen merken oder Dependencies manuell injizieren müssen. Dank PHP-Magie sind sie zugleich sehr gut testbar.Auf Scope-Creep achten
Ein Risiko beim Umgang mit Facades ist der „Scope-Creep” einer Klasse. Weil Facades so bequem verwendet werden können und keine Injektion erfordern, wachsen Klassen leicht unbemerkt. Mit Dependency Injection wirkt ein aufgeblähter Konstruktor als visuelles Warnzeichen. Achten Sie also besonders bei Facades darauf, den Verantwortungsbereich Ihrer Klassen klein zu halten.Facades vs. Dependency Injection
Ein zentraler Vorteil von Dependency Injection ist, dass die injizierte Implementierung austauschbar ist – nützlich beispielsweise für Tests, wo Sie Mocks oder Stubs injizieren und Aufrufe verifizieren können. Rein statische Methoden lassen sich normalerweise weder mocken noch stubben. Da Facades aber Aufrufe an das aus dem Container aufgelöste Objekt delegieren, können Sie eine Facade genauso testen wie eine injizierte Instanz.Cache::get mit den erwarteten Argumenten aufgerufen wurde.
Facades vs. Helper-Funktionen
Ergänzend zu Facades bringt Laravel Helfer-Funktionen mit, mit denen sich häufige Aufgaben erledigen lassen: Views erzeugen, Events feuern, Jobs dispatchen, HTTP-Antworten senden usw. Viele Helper machen dasselbe wie ihre entsprechenden Facades.Realtime Facades
Mit Realtime Facades können Sie jede Klasse Ihrer Anwendung wie eine Facade verwenden. Zur Verdeutlichung sehen wir uns zuerst Code ohne Realtime Facade an. Angenommen, das ModellPodcast besitzt eine Methode publish. Zum Veröffentlichen eines Podcasts wird jedoch eine Publisher-Instanz benötigt.
Publisher nicht mehr explizit übergeben – die Testbarkeit bleibt trotzdem erhalten. Für eine Realtime Facade stellen Sie dem Namespace der zu importierenden Klasse Facades voran.
Facades folgt.
Facades testen
Zum Testen von Facades verwenden Sie die MethodeshouldReceive, die eine Mockery-Instanz zurückgibt. Da Facades von Laravels Service Container aufgelöst und verwaltet werden, sind sie deutlich besser testbar als klassische statische Klassen.
| Methode | Beschreibung |
|---|---|
shouldReceive('method') | Erwartet, dass die Methode aufgerufen wird |
once() | Erwartet genau einen Aufruf |
times(n) | Erwartet n Aufrufe |
with(args) | Erwartet Aufruf mit bestimmten Argumenten |
andReturn(value) | Gibt den angegebenen Wert zurück |
andReturnNull() | Gibt null zurück |
Übersicht wichtiger Facades
Zuordnung häufig genutzter Facades zu ihren konkreten Klassen und den Bindungen im Service Container:| Facade | Klasse | Bindung |
|---|---|---|
App | Illuminate\Foundation\Application | app |
Auth | Illuminate\Auth\AuthManager | auth |
Cache | Illuminate\Cache\CacheManager | cache |
Config | Illuminate\Config\Repository | config |
Cookie | Illuminate\Cookie\CookieJar | cookie |
Crypt | Illuminate\Encryption\Encrypter | encrypter |
DB | Illuminate\Database\DatabaseManager | db |
Event | Illuminate\Events\Dispatcher | events |
File | Illuminate\Filesystem\Filesystem | files |
Gate | Illuminate\Contracts\Auth\Access\Gate | — |
Hash | Illuminate\Contracts\Hashing\Hasher | hash |
Http | Illuminate\Http\Client\Factory | — |
Log | Illuminate\Log\LogManager | log |
Mail | Illuminate\Mail\Mailer | mailer |
Notification | Illuminate\Notifications\ChannelManager | — |
Queue | Illuminate\Queue\QueueManager | queue |
RateLimiter | Illuminate\Cache\RateLimiter | — |
Redirect | Illuminate\Routing\Redirector | redirect |
Request | Illuminate\Http\Request | request |
Route | Illuminate\Routing\Router | router |
Schema | Illuminate\Database\Schema\Builder | — |
Session | Illuminate\Session\SessionManager | session |
Storage | Illuminate\Filesystem\FilesystemManager | filesystem |
URL | Illuminate\Routing\UrlGenerator | url |
Validator | Illuminate\Validation\Factory | validator |
View | Illuminate\View\Factory | view |
Nächste Schritte
Contracts
Lernen Sie das Gegenstück zu Facades kennen und erfahren Sie, wann welches Konzept passt.