Le interrogazioni al database e le chiamate ad API esterne hanno un alto costo in CPU e rete e possono impiegare diversi secondi.
Se recuperi ripetutamente gli stessi dati, salvare il risultato in cache ti permette di gestire le richieste successive molto più velocemente.Laravel offre un’API unificata compatibile con vari backend di cache: Memcached, Redis, DynamoDB, database e altri.
Di default è configurato il driver database. Passando a Redis o Memcached ottieni una cache ancora più veloce.
L’operazione più usata. Se la chiave è in cache, restituisce quel valore; altrimenti esegue la closure e salva il risultato.
$users = Cache::remember('users', 3600, function () { return DB::table('users')->get();});
Con Cache::remember() scrivi i tre passaggi “controlla cache → altrimenti calcola → salva in cache” in una sola riga. Ideale per query DB e risposte API.
$value = Cache::rememberForever('users', function () { return DB::table('users')->get();});
Se vuoi sapere se il valore proviene dalla cache o è stato appena calcolato, usa rememberWithWarmth(). Restituisce un array con il valore e un booleano che indica se era “caldo” (cache hit).
[$value, $warm] = Cache::rememberWithWarmth('users', 3600, function () { return DB::table('users')->get();});if ($warm) { // Valore dalla cache} else { // Appena calcolato dalla closure}
rememberWithWarmth() è utile per monitorare l’efficienza della cache. Se $warm è spesso false, valuta di aumentare il TTL.
Stale While Revalidate (aggiornamento flessibile della cache)
Con Cache::flexible() indichi in un array il periodo “fresco” e il periodo “utilizzabile anche se vecchio”.
Restituisce i dati vecchi all’utente aggiornando la cache in background.
// [periodo fresco (s), periodo utilizzabile anche se vecchio (s)]$value = Cache::flexible('users', [5, 10], function () { return DB::table('users')->get();});
Il driver memo mantiene in memoria l’accesso alla cache durante la stessa richiesta.
Utile quando accedi ripetutamente alla stessa chiave per ridurre i round trip verso lo store.
use Illuminate\Support\Facades\Cache;// Memo dello store predefinito$value = Cache::memo()->get('key');// Memo dello store Redis$value = Cache::memo('redis')->get('key');
// Primo accesso: raggiunge lo store$value = Cache::memo()->get('key');// Accessi successivi: restituiti dalla memoria (nessun accesso allo store)$value = Cache::memo()->get('key');
// Elimina tutte le voci con tag 'people' e 'authors' (elimina sia John sia Anne)Cache::tags(['people', 'authors'])->flush();// Elimina solo con tag 'authors' (elimina solo Anne; John resta)Cache::tags('authors')->flush();
I tag sono utili per invalidare gruppi (per utente, per articolo, ecc.).
Es.: Cache::tags(['user', "user:{$userId}"])->flush() per svuotare la cache di uno specifico utente.
Attende al massimo i secondi indicati per ottenere il lock. Al timeout viene lanciata LockTimeoutException.
use Illuminate\Contracts\Cache\LockTimeoutException;$lock = Cache::lock('foo', 10);try { $lock->block(5); // Attesa max 5 secondi // Elaborazione dopo aver ottenuto il lock} catch (LockTimeoutException $e) { // Lock non ottenuto} finally { $lock->release();}
Con closure è più conciso.
Cache::lock('foo', 10)->block(5, function () { // Attende max 5s, esegue e rilascia});
Modo semplice per evitare esecuzioni multiple della stessa logica.
Cache::withoutOverlapping('foo', function () { // Solo una alla volta});// Personalizza i tempiCache::withoutOverlapping('foo', function () { // ...}, lockFor: 120, waitFor: 5);
Ottieni il lock in una richiesta web e lo rilasci in un job in coda.
// Nella richiesta: ottieni il lock e dispatcha il job$lock = Cache::lock('processing', 120);if ($lock->get()) { ProcessPodcast::dispatch($podcast, $lock->owner());}// Nel job: rilascia il lockCache::restoreLock('processing', $this->owner)->release();
Per forzare il rilascio indipendentemente dall’owner corrente usa forceRelease.
Per estendere la scadenza del lock in tuo possesso usa refresh. Senza argomenti usa la durata originale. Utile per elaborazioni lunghe con lock brevi che vuoi rinnovare periodicamente.
$lock = Cache::lock('generate-reports', 60);if ($lock->get()) { foreach ($reports as $report) { $report->generate(); // Rinnova per altri 60 secondi $lock->refresh(); } $lock->release();}
L’helper cache() fa le stesse cose della facade in modo più conciso.
// Leggi$value = cache('key');// Scrivi con scadenzacache(['key' => 'value'], $seconds);cache(['key' => 'value'], now()->addMinutes(10));// Senza argomenti ottieni la stessa istanza della facadecache()->remember('users', $seconds, function () { return DB::table('users')->get();});
use Illuminate\Support\Facades\Cache;use Illuminate\Support\Facades\DB;public function index(): array{ $users = Cache::remember('all-users', 3600, function () { return DB::table('users')->orderBy('name')->get(); }); return compact('users');}
2
Invalidare la cache all'aggiornamento
public function store(Request $request): RedirectResponse{ User::create($request->validated()); // Elimina la cache: verrà ricalcolata alla prossima lettura Cache::forget('all-users'); return redirect()->route('users.index');}