Un enum PHP (PHP 8.1+) definisce un tipo con un insieme fisso di valori possibili, i suoi case: enum Status { case Active; case Banned; }. Usi un case come Status::Active, e un parametro di tipo Status non accetta nient'altro. Un backed enum, enum Status: string, dà anche a ogni case un valore che puoi salvare e riconvertire con Status::from().
Prima degli enum, la stessa cosa era un elenco di costanti stringa, e nulla impediva a un errore di battitura come 'actve' di arrivare nel database. Con Status come tipo del parametro, si possono passare solo i tre case.
Enum puri e backed enum
Un enum puro ha case che sono solo nomi. Un backed enum dichiara un tipo dopo il nome, int o string, e ogni case deve allora avere un valore univoco di quel tipo. Ogni case ha ->name; solo i case backed hanno ->value.
Scegli un backed enum ogni volta che il valore esce dal programma: una colonna di database, un URL, un campo di un form, un JSON. Scegli un enum puro per i valori che esistono solo dentro il codice, come lo stato di un parser.
Convertire un valore con from() e tryFrom()
I backed enum hanno due metodi statici per riconvertire un valore salvato in un case. from() lancia un ValueError per un valore sconosciuto; tryFrom() restituisce null, che si abbina bene a ?? per un default:
Usa tryFrom() su tutto ciò che ti ha inviato un utente, e from() sui valori scritti dal tuo codice, dove un valore sconosciuto significa un bug che vuoi scoprire. L'argomento segue le normali regole sui tipi dei parametri: su un enum int, Priority::from('5') restituisce Priority::Normal nella modalità di default perché '5' viene prima convertito in 5, Priority::from('5x') è un TypeError, e con declare(strict_types=1) qualsiasi stringa è un TypeError. Questo vale anche per tryFrom(): Priority::tryFrom('abc') lancia un errore invece di restituire null, quindi verifica prima l'input di un form per un enum int con filter_var($raw, FILTER_VALIDATE_INT).
Elencare tutti i case con cases()
Enum::cases() restituisce un array con ogni case, nell'ordine in cui sono dichiarati. È così che costruisci un menu a tendina, validi una lista o ottieni tutti i valori con array_column:
Eseguilo, scegli un piano e premi Choose: lo stesso script viene eseguito di nuovo con $_POST['plan'] compilato, e tryFrom() riconverte la stringa inviata in un case di Plan. Un valore falsificato come plan=gold dà null, e nessuna opzione viene selezionata.
Metodi, costanti e interfacce degli enum
Gli enum possono avere metodi, metodi statici e costanti, e possono implementare interfacce. Dentro un metodo, $this è il case corrente, il che rende match ($this) il modo naturale di associare dati a ogni case. Ciò che un enum non può avere sono le proprietà: i dati per case vengono dai metodi.
Enum in match
match confronta con ===, e un case di un enum è identico solo a se stesso, quindi match e gli enum vanno d'accordo. Se dimentichi un case e quel case arriva al match, PHP lancia un UnhandledMatchError invece di non restituire nulla in silenzio:
Vedi match per come match differisce da switch.
Enum in JSON e come stringhe
json_encode() scrive un case backed come il suo valore. Un enum puro non si può codificare, e l'echo di qualsiasi case fallisce, perché un enum è un oggetto, non una stringa. Stampa invece ->value o ->name:
echo Role::Admin; lancia un Error ("Object of class Role could not be converted to string"), e gli enum non possono implementare __toString(). Al ritorno, il JSON dà una semplice stringa, quindi convertila con from() o tryFrom() come mostrato. Altro sulla codifica in json_encode.
Errori comuni con gli enum
Tre errori ricorrono spesso. Un case non è mai uguale al suo valore, un case non può essere una chiave di array, e new non funziona su un enum:
Se ti serve una mappa con i case stessi come chiavi, usa SplObjectStorage o WeakMap, che accettano oggetti come chiavi.
Domande frequenti
Come ottengo il valore di un enum in PHP?
Su un backed enum, leggi ->value: Status::Active->value vale 'active'. Ogni case ha anche ->name, il nome del case come stringa ('Active'). Un enum puro (senza : string o : int) ha solo ->name.
Qual è la differenza tra from() e tryFrom() negli enum PHP?
Entrambi trasformano un valore in un case di un backed enum. Status::from('active') restituisce il case oppure lancia un ValueError quando nessun case ha quel valore; Status::tryFrom('nope') restituisce invece null. Usa tryFrom() per l'input dell'utente e from() quando un valore errato è un bug.
Come ottengo tutti i valori di un enum in PHP?
Status::cases() restituisce ogni case nell'ordine di dichiarazione. Per i valori di un backed enum usa array_column(Status::cases(), 'value'), e per i nomi array_column(Status::cases(), 'name').
Qual è la differenza tra un enum puro e un backed enum?
Un enum puro (enum Suit { case Hearts; }) ha case che sono solo nomi. Un backed enum (enum Suit: string { case Hearts = 'H'; }) dà a ogni case un valore int o string univoco, che ti serve per salvarlo in un database, metterlo in un form o in un JSON e riconvertirlo con from() o tryFrom().
Un enum PHP può avere metodi?
Sì. Gli enum possono avere metodi, metodi statici e costanti, e possono implementare interfacce. Dentro un metodo, $this è il case corrente, quindi return match ($this) { self::Active => 'green', self::Banned => 'red' }; è uno schema comune. Gli enum non possono avere proprietà.