Zum Hauptinhalt springen
Wenn ein Paket ein eigenes Cache-Backend bereitstellen soll, trennen Sie den Store, der das Speichern implementiert, vom Repository, das die Laravel-API bereitstellt. Mit Cache::extend() registrieren Sie eine Erzeugungsmethode; Laravel umhüllt den zurückgegebenen Store nicht automatisch mit einem Repository. Diese Seite basiert auf der Implementierung von Laravel Framework v13.39.0. Die Grundlagen finden Sie unter Cache, die Vorbereitung des Providers unter Paketentwicklung.

Treibername und Store-Name trennen

CacheManager::build() ruft eine eigene Erzeugungsmethode für das konfigurierte driver auf, sofern vorhanden, und zwar noch vor den eingebauten Treibern. Verwenden Sie daher keine Namen wie redis oder array erneut, sondern einen paketspezifischen Namen.

Vor dem boot anderer Provider registrieren

Wenn ein anderes Paket den Cache in seinem boot() verwendet, kann eine Registrierung des Treibers in Ihrem eigenen boot() je nach Reihenfolge zu spät kommen. Registrieren Sie gemäß der offiziellen Dokumentation in register() einen booting-Callback der Anwendung. Das folgende Minimalbeispiel verwendet den Standard-ArrayStore, um den Registrierungsweg ohne externen Dienst zu prüfen. Es wird in src/MemoServiceProvider.php des Pakets Acme\Memo abgelegt.
Den Provider laden Sie etwa über die automatische Paketerkennung. Da dieser Provider nur die Erweiterung registriert, machen Sie ihn nicht zu einem verzögerten (deferred) Provider, damit er sowohl bei HTTP als auch bei Artisan geladen wird.
  • Das booting der Anwendung wird beim normalen Start ausgeführt, nachdem register() aller Provider abgeschlossen ist und bevor die jeweiligen boot() laufen. Es ist nicht dasselbe wie $this->booting() des Providers selbst.
  • Der Callback von extend() erhält die Anwendung und das Konfigurations-Array des Stores. Erzeugen Sie den Store und bauen Sie externe Verbindungen in diesem Erzeugungs-Callback auf.
  • Dieser Registrierungszeitpunkt garantiert nicht die Nutzung des Caches innerhalb von register() anderer Provider. Trennen Sie die Registrierung von Diensten von ihrer tatsächlichen Nutzung.
Wenn Sie lediglich einen Standard-In-Memory-Cache benötigen, genügt der Treiber array. Dieses Beispiel dient der Erläuterung von Registrierung und Verträgen und eignet sich weder für prozessübergreifendes Teilen noch für Persistenz. Bei einem eigenen Backend ersetzen Sie die Erzeugung des ArrayStore durch eine Klasse, die Illuminate\Contracts\Cache\Store implementiert.
CacheManager::extend() bindet den Scope anonymer Closures an den Manager neu. Gehen Sie nicht davon aus, dass $this in einer nicht-statischen Closure der Provider ist, sondern verwenden Sie wie im Beispiel eine statische Closure und das Argument $app.

Den Store in der nutzenden Anwendung hinzufügen

Fügen Sie das folgende Element dem bestehenden stores-Array in config/cache.php hinzu. Gestalten Sie das Paket nicht so, dass es default oder das gesamte stores der nutzenden Anwendung überschreibt.
Auch wenn Sie den Store per CACHE_STORE als Standard festlegen möchten, geben Sie dort nicht den Treibernamen an, sondern den Store-Namen catalog. Legen Sie mehrere Konfigurationen mit demselben Treiber an, wird für jeden Store-Namen ein eigenes Repository erzeugt.

Das Repository selbst zusammensetzen

CacheManager::callCustomCreator() gibt den Rückgabewert des Callbacks unverändert zurück. Geben Sie nur einen Store zurück, funktionieren zwar get() und put(), aber remember() und andere Methoden des Repositorys stehen nicht zur Verfügung, und auch die Interpretation der TTL ändert sich. repository($store, $config) im Beispiel übernimmt Folgendes:
  • Es umhüllt den Store mit Illuminate\Cache\Repository.
  • Es übergibt den vom Manager zur Konfiguration hinzugefügten store-Namen an das Repository.
  • Ist ein Event-Dispatcher registriert und die Einstellung events nicht deaktiviert, setzt es den Dispatcher im Repository.
Dabei werden nicht alle eigenen Einstellungen auf den Store angewendet. Verbindungsziel, Präfix, Serialisierung usw. setzen Sie in der Store-Implementierung und in der Erzeugungsmethode um. Das gilt auch für serialize, das im Beispiel aus der Konfiguration gelesen wird.

Den Store-Vertrag mit der aktuellen Implementierung abgleichen

Implementieren Sie die Methoden, die Illuminate\Contracts\Cache\Store in Laravel 13 verlangt. Verteilen Sie keine Liste leerer Methoden aus älteren Beispielen als funktionierenden Treiber. null wird vom Repository als Cache-Miss behandelt. Implementieren Sie den Store so, dass false oder 0 nicht als fehlend gelten. Auch das Speichern von null dient nicht als Markierung, die eine Neuberechnung durch remember() verhindert.

Die TTL über das Repository prüfen

Repository::put() verarbeitet die TTL, bevor sie an den Store übergeben wird.
Der ArrayStore im Beispiel speichert einen Eintrag ohne Ablaufzeit, wenn Sie direkt an put() 0 Sekunden übergeben. put(..., 0) am Repository bedeutet dagegen Löschen. Wenn Sie nur den mit getStore() geholten Low-Level-Store testen, prüfen Sie nicht das Verhalten der API, die Nutzer tatsächlich aufrufen.

add, Locks und Tags gesondert prüfen

Allein die Implementierung des Store-Vertrags garantiert nicht die Unterstützung aller Cache-Funktionen.
  • Atomares add(): Ist nicht Teil des Store-Vertrags. Bei einem Aufruf mit positiver TTL verwendet das Repository add() des Stores, sofern vorhanden. Andernfalls greift ein Fallback über get() und put(), sodass das bloße Umhüllen mit einem Repository keine Atomarität garantiert. Implementieren Sie es bei geteilten Backends mit den atomaren Operationen des jeweiligen Backends und prüfen Sie auch die gleichzeitige Ausführung.
  • Locks: lock() und restoreLock() aus Illuminate\Contracts\Cache\LockProvider sind ein separater Vertrag. Prüfen Sie das Erwerben, die Übereinstimmung des Besitzers, den Ablauf und dass Locks anderer Besitzer nicht freigegeben werden. Die Locks des ArrayStore im Beispiel bieten keinen prozessübergreifenden gegenseitigen Ausschluss.
  • Tags: Das Repository prüft, ob der Store tags() besitzt. In der Regel ist eine Implementierung etwa mit TaggableStore nötig; allein durch den Store-Vertrag werden Tags nicht automatisch aktiviert.
Gehen Sie nicht davon aus, dass flush() eine teilweise Löschung unter Berücksichtigung des konfigurierten Präfixes ist. Prüfen Sie den Löschumfang bei geteilten Backends und erläutern Sie ihn den Nutzern, einschließlich php artisan cache:clear.

Vorhalten von Instanzen und Löschen von Daten unterscheiden

CacheManager ist ein Singleton und hält auch das Ergebnis von store('catalog') pro Store-Namen vor. Eine Konfigurationsänderung oder eine erneute Registrierung per extend() allein aktualisiert bereits erzeugte Repositorys nicht.
$same ist dasselbe Objekt wie $before. Erst beim Abruf nach forgetDriver() wird $after aus der neuen Konfiguration erzeugt. forgetDriver() löscht nicht das gesamte Backend. Da der ArrayStore im Beispiel die Daten jedoch innerhalb der Instanz hält, sind alte Daten im neuen Store nicht sichtbar. Außerdem werden alte Repository-Referenzen nicht ersetzt, die von $before auf Nutzerseite oder vom bereits aufgelösten Singleton cache.store gehalten werden. Aktualisieren Sie in Produktion den Konfigurations-Cache im Rahmen des regulären Deployments und starten Sie langlebige Worker neu. Berücksichtigen Sie auch die Lebensdauer von Services und behandeln Sie eine erneute Auflösung nicht als gleichzeitige Aktualisierung aller Prozesse.

Nicht nur Fassaden-Mocks, sondern den Erzeugungsweg testen

Leiten Sie in der Testumgebung für Pakete die Aufrufe durch den echten Manager und das echte Repository. Das folgende Testbench-Beispiel prüft, dass der Treiber auch im boot() eines zuvor registrierten anderen Providers verfügbar ist. Im Beispiel wird ein Array gespeichert, ohne die Wiederherstellungsbeschränkung von cache.serializable_classes zu ändern, und mit ArrayStore::all(false) wird auch der rohe gespeicherte Wert geprüft.
Bei einem eigenen Backend prüfen Sie zusätzlich Ablauf, fehlende Schlüssel bei many(), den Hin- und Rückweg von false und 0, touch(), Verbindungsfehler, gleichzeitige Aktualisierungen sowie Präfix und Löschumfang. Ein bloß erfolgreiches Cache::shouldReceive('get') ist kein Beleg für die Treiberregistrierung oder die Kompatibilität mit einem externen Dienst.

Checkliste für die langfristige Wartung

  • Machen Sie Treibernamen, Store-Konfiguration, Serialisierungsformat sowie Exceptions und Rückgabewerte im Fehlerfall zur öffentlichen Spezifikation.
  • Prüfen Sie die Methoden des Store-Vertrags und optionale Funktionen wie Tags und Locks für jede unterstützte Laravel-Version.
  • Prüfen Sie, dass die Registrierung auch bei einem Neustart mit Konfigurations-Cache funktioniert und der Treiber aus dem boot() anderer Provider nutzbar ist.
  • Kündigen Sie Kompatibilitätsänderungen an gespeicherten Daten zusammen mit einer Strategie für die Migration oder das Verwerfen bestehender Schlüssel an.
  • Unterscheiden Sie zwischen dem Vorhalten von Instanzen im Prozess, den Daten im Backend und dem Konfigurations-Cache.

Verwendete Primärquellen

Zuletzt geändert am 29. Oktober 2026