Una funzione anonima, chiamata anche closure, è una funzione senza nome. Scrivi function ($param) { ... } dove è atteso un valore: assegnala a una variabile, passala a un'altra funzione o restituiscila. Può portare con sé variabili del codice circostante con use ($var).
Ogni funzione anonima è un oggetto della classe predefinita Closure, ed è per questo che si può salvare, passare in giro e chiamare più tardi con $greet(...).
La parola chiave use cattura per valore
Una closure non può vedere da sola le variabili esterne. use ($x) copia il valore di $x nella closure nel momento in cui la closure viene creata, non quando viene eseguita:
use per riferimento: &$var
use (&$x) dà alla closure la variabile stessa invece di una copia. Le modifiche fatte dentro la closure sono visibili fuori, e quelle fatte fuori vengono viste dentro. È così che una callback aggiunge a un totale o tiene un contatore.
Ogni chiamata a makeCounter() crea un nuovo $count, e la closure restituita lo mantiene in vita dopo che la funzione è terminata. È a questo che si riferisce "closure": la funzione si chiude sulle variabili di cui ha bisogno.
Passare una closure come callback
Funzioni come array_map(), array_filter(), usort() e array_walk() accettano una funzione come argomento. Una closure ti permette di scriverla sul posto, con tutte le istruzioni che il lavoro richiede:
Quando il corpo è una singola espressione, una arrow function come fn($p) => $p['price'] è più breve e non richiede use.
Callable: nomi di funzione, metodi e strlen(...)
Un parametro con tipo callable accetta più delle closure. Valgono una stringa con il nome di una funzione, un array con un oggetto e il nome di un metodo, e un array con il nome di una classe e il nome di un metodo statico. Da PHP 8.1, la sintassi first-class callable strlen(...) trasforma direttamente ciascuno di questi in una Closure.
La forma (...) viene verificata quando la riga viene eseguita: un errore di battitura lancia subito un Error. Una stringa come 'strtoupr' resta solo una stringa finché qualcuno non prova a chiamarla.
Closure dentro una classe: $this e static
Una closure creata dentro un metodo ha $this collegato automaticamente, quindi può usare le proprietà dell'oggetto. Dichiarala static function quando non le serve $this, il che le impedisce anche di tenere in vita l'oggetto.
Dimenticare use
Il bug più comune con le closure è usare una variabile esterna senza elencarla in use. Dentro la closure la variabile non esiste:
$minAge = 18;
$adults = array_filter($people, function ($p) {
return $p['age'] >= $minAge; // $minAge is not in use (...)
});
PHP prints: Warning: Undefined variable $minAge
$minAge dentro è null, ogni età confrontata con >= null è true, e ogni persona supera il filtro. Su un server che nasconde i warning, nulla te lo segnala. Aggiungi la variabile a use:
Domande frequenti
Cos'è una closure in PHP?
Una funzione senza nome, creata con function (...) { ... } e salvata in una variabile o passata come argomento. PHP la rappresenta come un oggetto della classe Closure. Può portare con sé variabili dello scope in cui è stata creata, elencate in use (...).
Cosa fa la parola chiave use in una closure PHP?
use ($x) copia la variabile esterna $x nella closure quando la closure viene creata. Le modifiche successive a $x fuori non vengono viste. Scrivi use (&$x) per condividere invece la variabile, così le modifiche valgono in entrambe le direzioni.
Cos'è un callable in PHP?
Qualsiasi cosa PHP possa chiamare: una closure, il nome di una funzione come stringa ('strtoupper'), un array [$object, 'method'] o [ClassName::class, 'staticMethod'], oppure un oggetto con __invoke(). Usa il tipo callable per accettarli tutti e is_callable() per verificarli.
Cosa significa strlen(...) in PHP?
È la sintassi first-class callable di PHP 8.1: strlen(...) crea una Closure dalla funzione senza chiamarla. Funziona anche per i metodi, $obj->method(...), e per i metodi statici, Foo::bar(...), e viene verificata quando la riga viene eseguita, a differenza di un nome in una stringa.
Serve un punto e virgola dopo una funzione anonima?
Sì, quando la assegni: $f = function () { ... }; è un'istruzione di assegnazione, quindi termina con ;. Ometterlo è un errore di parsing. Una closure passata direttamente come argomento non ha bisogno di un punto e virgola proprio.