Dopo aver analizzato gli errori in PHP, in questa nuova guida introdurremo le eccezioni e impareremo a gestirle all'interno delle nostre applicazioni tramite il costrutto try-catch-finally
che il linguaggio mette a disposizione.
Indice dei contenuti
Un'eccezione è un segnale che indica che si è verificato un errore all'interno della nostra applicazione. Le cause scatenanti un'eccezione possono essere diverse:
PHP fornisce un potente meccanismo di gestione delle eccezioni, introdotto a partire da PHP 5, che consente di gestirle in modo elegante. A differenza del tradizionale sistema di controllo degli errori di PHP, la gestione delle eccezioni avviene tramite l'utilizzo degli oggetti, il che fornisce più controllo e flessibilità.
PHP ha un modello di eccezione simile a quello di altri linguaggi di programmazione. Infatti un'eccezione può essere lanciata e "catturata" racchiudendo il codice in un blocco try
, Ciascun blocco try
deve poi avere almeno un blocco catch
corrispondente, oppure un blocco finally
.
Prima di fare un esempio elenchiamo nel dettaglio le parole chiavi utilizzate:
try
: è il blocco all'interno del quale inserire il codice che potrebbe generare un errore. Se non viene generato nessun errore, il codice continua normalmente altrimenti viene sollevata un'eccezionethrow
: tramite questo costrutto si attiva un'eccezione. Ciascun throw
deve avere almeno un catch
catch
: un blocco "catch"
recupera un'eccezione e crea un oggetto di tipo Exception
contenente le informazioni sull'eccezionefinally
: questo blocco viene sempre eseguitoVediamo un esempio per capire meglio il funzionamento del costrutto try-catch-finally
<?php
function division(int $x, int $y)
{
if ($y == 0) {
throw new Exception('Divisione per zero');
}
return $x/$y;
}
try {
printf("%f<br>", division(5, 0));
} catch (Exception $e) {
printf("Eccezione catturata: %s<br>", $e->getMessage());
} finally {
printf("Blocco finally sempre eseguito<br>");
}
try {
printf("%f<br>", division(5, 2));
} catch (Exception $e) {
printf("Eccezione catturata: %s<br>", $e->getMessage());
} finally {
printf("Blocco finally sempre eseguito<br>");
}
In questo esempio abbiamo definito la funzione division()
che restituisce la divisione tra 2 numeri. La funzione genera un'eccezione nel caso in cui il valore del divisore (argomento $y
) sia uguale a zero.
L'eccezione viene generata tramite il costrutto throw new Exception
, dove Exception
è la classe predefinita di PHP che gestisce tutte le eccezioni a livello utente.
In breve, il codice che potrebbe generare un'eccezione viene incluso dentro il blocco try, nel nostro caso la divisione per zero. L'eventuale eccezione viene gestita tramite il blocco catch, all'interno del quale viene specificato il tipo di eccezione da gestire, nel nostro esempio l'eccezione generica Exception
.
Quindi possiamo accedere al messaggio contenente l'errore tramite il metodo getMessage()
della classe Exception
.
Infine il blocco finally
, che è opzionale e raramente utilizzato, viene sempre eseguito a prescindere che l'eccezione venga o meno sollevata.
L'output dell'esempio precedente è il seguente
Eccezione catturata: Divisione per zero
Blocco finally sempre eseguito
2.500000
Blocco finally sempre eseguito
division()
viene chiamata con il dividendo pari a 2, in questo caso la divisione avviene correttamenteNota: a partire da PHP 7.1 è possibile utilizzare il catch multiplo, ossia la possibilità di specificare più tipologie di eccezioni in una stessa istruzione catch. È sufficiente separare ciascuna eccezioni tramite il carattere pipe (|)
Esempio:
<?php
try {
// codice
} catch (ExceptionType1 | ExceptionType2 $e) {
// codice in caso di eccezione catturata
} catch (Exception $e) {
// codice in caso di eccezione catturata
}
Con l'arrivo di PHP 7 tutte le eccezioni implementano adesso l'interfaccia Throwable:
<?php
Throwable {
abstract public string getMessage()
abstract public int getCode()
abstract public string getFile()
abstract public int getLine()
abstract public array getTrace()
abstract public string getTraceAsString()
abstract public Throwable getPrevious()
abstract public string _toString()
}
Ciascun oggetto di tipo Exception in PHP può quindi usufruire delle seguenti funzioni:
getMessage()
: ritorna il messaggio dell'eccezionegetCode()
: ritorna il codice dell'eccezionegetFile()
: ritorna il file che ha generato l'eccezionegetLine()
: ritorna la linea contenente l'errore che ha generato l'eccezionegetTrace()
: ritorna un array contenente il trace
, ossia le istruzioni che hanno generato l'eccezionegetTraceAsString()
: ritorna il trace in formato stringagetPrevious()
: ritorna l'eccezione precedente generata_toString()
: ritorna un'eccezione in formato stringaPer creare un gestore di eccezioni personalizzato è necessario creare una classe speciale con funzioni che possono essere chiamate quando si verifica un'eccezione in PHP. La classe deve essere un'estensione della classe Exception
.
La classe di eccezione personalizzata eredita le proprietà dalla classe Exception
di PHP ed è possibile integrarvi ulteriori funzioni personalizzate.
Facciamo un esempio per capire meglio:
<?php
class customException extends Exception
{
public function errorMessage() {
return 'Errore alla riga ' . $this->getLine() .
' nel file ' . $this->getFile() .
': <strong>'.$this->getMessage().'</strong> non è un indirizzo email valido';
}
}
$email = "pippo@.com";
try {
if(filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
throw new customException($email);
}
} catch (customException $e) {
echo $e->errorMessage();
}
La classe customException non è altro che una copia della classe Exception con l'aggiunta della funzione errorMessage(). In gergo informatico customException è detta classe "figlia", mentre Exception è la classe padre, dalla quale CustomException eredita (tramite la parola chiave extends
) le proprietà e i metodi, inclusi getLine() e getFile() e getMessage().
Il codice sopra genera un'eccezione e la cattura tramite la classe di eccezione personalizzata customException:
Un metodo alternativo per gestire le eccezioni è quello di utilizzare la funzione set_exception_handler() del linguaggio, che permette all'utente di definire e impostare una propria funzione di gestione delle eccezioni.
Nella pratica, è molto difficile catturare ogni possibile eccezione che un programma può generare, la funzione set_exception_handler() quindi consente di gestire anche le eccezioni non rilevate attraverso un normale blocco try/catch.
La funzione set_exception_handler() accetta come parametro il nome di una funzione in cui è possibile inserire il codice per gestire le eccezioni non rilevate. Questa funzione deve essere definita prima di chiamare set_exception_handler().
Vediamo un esempio di utilizzo:
<?php
function exception_handler($exception)
{
echo "Eccezioni non catturate: " . $exception->getMessage() . "<br>";
}
set_exception_handler('exception_handler');
throw new Exception('eccezione non trovata');
echo "non viene eseguito";
che produce il seguente output
Eccezioni non catturate: eccezione non trovata