Sin da PHP 5.1.0 noi sviluppatori abbiamo accesso alle SPL Exceptions. Come già vi accennavo nel post sull’utilizzo dell’autoloading SPL, la Standard PHP Library è già inclusa in PHP e ci mette a disposizione svariate utility, sotto forma di classi, interface ed exception pronte da utilizzare o da estendere. Ci semplificano la vita quando lavoriamo ad un progetto e possono farci risparmiare del tempo, così da dedicarlo al progetto vero e proprio.
In questa mini guida vedremo come sfruttare le Exception che la libreria SPL ci mette a disposizione, analizzandole singolarmente. Sinora magari abbiamo utilizzato direttamente la \Exception “base” oppure abbiamo scritto le nostre Exception che la ereditano direttamente. Sfruttando invece le Exception SPL, potremmo utilizzare (o ereditare) eccezioni più specifiche, con compiti separati.
In cosa consistono le SPL Exceptions?
Un set di 13 Exception che estendono (indirettamente) la \Exception base e che proprio per questa natura non si usano in modo speciale, ma come delle “semplici” eccezioni, ma con compiti specifici.
Perché dovrei usarle?
La loro particolarità sta nel fatto che possiamo dettagliare la gestione degli errori. È infatti sbagliato avere 100 righe di codice che generano una semplice Exception senza specificare i vari tipi di errori che possono accadere. Idealmente, potremmo avere le nostre Exception che estendono le funzionalità o di quella base o appunto delle SPL Exception, ma non è molto pratico, almeno per i principianti.
Questo perché le SPL Exception coprono un vasto range di situazioni tipiche che possiamo incontrare, come ad esempio un parametro non valido per un metodo o una funzione (InvalidArgumentException), oppure un overflow (OverflowException), oppure quando ci aspettiamo un array ma ci viene restituito una stringa (InvalidArgumentException)
Come scegliere la Exception appropriata
Spesso scegliere l’Exception da generare è abbastanza ovvio, ma in molti casi invece l’errore è più astratto e potrebbe coinvolgere due o tre tipi di Exception. In questi casi è corretto generare l’Exception genitore. Infatti, tutte le eccezioni della SPL library estendono due classi principali:
LogicException che include le seguenti sottoclassi:
- BadFunctionCallException
- BadMethodCallException
- DomainException
- InvalidArgumentException
- LengthException
- OutOfRangeException
RuntimeException che include le seguenti sottoclassi:
- OutOfBoundsException
- OverflowException
- RangeException
- UnderflowException
- UnexpectedValueException
Le 13 Exception SPL, una per una
LogicException
Come abbiamo visto dall’elenco qui sopra, questa è una classe che racchiude circa la metà delle altre Exception, al pari di RuntimeException. Come ci suggerisce il nome, una LogicException dovrebbe gestire gli errori in quei casi nei quali il nostro codice non si comporta come dovrebbe, principalmente per un nostro difetto di progettazione. Chiedere valori che non esistono, chiamare metodi non definiti, sbagliare il numero di parametri di una funzione, etc. Insomma, roba che non dovrebbe esistere in un mondo perfetto.
BadFunctionCallException
Questo errore è poco diffuso, e andrebbe generato ad esempio quando una funzione di callback non esiste o un suo parametro è sbagliato.
BadMethodCallException
Questa è una sottoclasse di BadFunctionCallException e funziona in modo del tutto simile, soltanto essa è riferita ad un metodo di una classe anziché una funzione generica. In modo analogo alla precedente, dovrebbe essere generata quando manca un parametro o l’intero metodo non esiste.
DomainException
Questa Exception deve essere usata quando un valore non rientra tra quelli contemplati.
Facciamo un esempio: data una funzione che simula il tiro di un dado, ci aspettiamo che il numero risultante sia compreso tra 1 e 6. Se non lo fosse, potremmo generare appunto una DomainException.
InvalidArgumentException
Ecco un’altra Exception molto utilizzata. Possiamo generarla quando un parametro (di un metodo o di una funzione) non è valido, nel senso che non è del tipo che ci aspettiamo. Ad esempio, se ci aspettiamo che $input sia un array, dovremmo generare una InvalidArgumentException se non lo è: !is_array( $input ) .
LengthException
Questa Exception è progettata per essere utilizzata quando la lunghezza di una stringa non è valida, troppo corta o troppo lunga. Per esempio, se ci aspettiamo che $codice sia un codice a barre ISBN-10, che è lungo 9 caratteri. e non ha questa lunghezza strlen( $codice ) != 9 , dovremo generare una LengthException.
OutOfBoundsException
Una OutOfBoundsException dovrebbe essere generata se una chiave non è presente in un array, ad esempio $array[‘chiave-non-esistente’] . Se invece abbiamo a che fare con una chiave che è un integer inesistente, dovremmo usare OutOfRangeException descritta di seguito.
RuntimeException
Proprio come per LogicException questa è una classe genitore che accorpa circa metà delle SPL Exceptions e dovrebbe essere generata quando avvengono errori in fase di esecuzione, magari per un input sbagliato dell’utente o in generale per quelle situazioni dove abbiamo “meno controllo”: quando un database non è disponibile, un file non può essere scritto, etc.
OutOfRangeException
Questa Exception è molto simile a OutOfBoundsException descritta in precedenza, la differenza è che questa dovrebbe essere generata se la chiave inesistente di un array è numerica, quindi di tipo integer.
OverflowException
Questa Exception può risultare utile quando, aggiungendo un elemento ad un container (in senso generico), quest’ultimo risulta pieno. Possiamo utilizzarla anche nei casi nei quali abbiamo raggiunto ad esempio un “numero massimo di tentativi” $i > $numeroTentativi.
UnderflowException
All’opposto della precedente Exception, c’è UnderflowException, che dovrebbe essere generata quando aggiungiamo un elemento ad un container vuoto. Se ad esempio il nostro codice prova a togliere un elemento da un container che però risulta vuoto, potremmo generare appunto una UnderflowException.
RangeException
Molto simile a DomainException, questa RangeException è molto utile quando un determinato valore non rientra in un range numerico prefissato. Ad esempio, se ci aspettiamo che $numero sia compreso tra 50 e 100 ($numero >= 50 && $numero <= 100) e non lo è, potremmo generare una RangeException.
UnexpectedValueException
Da non confondere con InvalidArgumentException (che verifica il tipo di un dato), questa Exception dovrebbe essere generata se un dato non è compreso in un set di valori.