Eccezioni PHP

Eccezioni PHP

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.

Cos'è un'eccezione

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à.

Try-catch-finally e classe Exception

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'eccezione
  • throw: 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'eccezione
  • finally: questo blocco viene sempre eseguito

Vediamo 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
  • La riga 1 è generata dall'eccezione sollevata quando la funzione division() viene chiamata con il dividendo uguale a 0
  • Le righe 2 e 4 vengono generata dai blocchi finally, sempre eseguiti
  • La riga 3 è generata quando la funzione division() viene chiamata con il dividendo pari a 2, in questo caso la divisione avviene correttamente

Nota: 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
}

Interfaccia Throwable

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'eccezione
  • getCode(): ritorna il codice dell'eccezione
  • getFile(): ritorna il file che ha generato l'eccezione
  • getLine(): ritorna la linea contenente l'errore che ha generato l'eccezione
  • getTrace(): ritorna un array contenente il trace, ossia le istruzioni che hanno generato l'eccezione
  • getTraceAsString(): ritorna il trace in formato stringa
  • getPrevious(): ritorna l'eccezione precedente generata
  • _toString(): ritorna un'eccezione in formato stringa

Gestore eccezioni personalizzato

Per 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:

  1. La classe customException viene creata come estensione della classe Exception. In questo modo ne eredita tutti i metodi e le proprietà
  2. Viene creata la funzione errorMessage(). Questa funzione restituisce un messaggio di errore se un indirizzo e-mail non è valido
  3. La variabile $email è impostata su una stringa che non è un indirizzo di posta elettronica valido
  4. Il blocco "try" viene eseguito e viene generata un'eccezione poiché l'indirizzo e-mail non è valido
  5. Il blocco "catch" rileva l'eccezione e visualizza il messaggio di errore

La funzione set_exception_handler()

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

Sviluppatore PHP Freelance

Stai cercando uno sviluppatore PHP? Ho oltre 10 anni di esperienza nello sviluppo web con questo linguaggio.

Contattami adesso!