Categorie
PHP

PHP – Gestione delle Eccezioni

Le eccezioni forniscono un meccanismo unificato per la gestione degli errori in modo estensibile, manutenibile, ed object-oriented.
L’idea di base è che il codice è eseguito all’interno di un blocco try, con un codice simile al seguente:

 

try
{
  // tuo codice
}

Se qualcosa va storto all’interno del blocco try, si può creare quella che viene chiamata un’eccezione.
Alcuni linguaggi, come Java, generano in certi casi, automaticamente delle eccezioni per noi.
In PHP, le eccezioni devono essere generate manualmente. Si genera un’eccezione come segue:

 

throw new Exception('messaggio', codice);

 

La parola chiave throw innesca il meccanismo di gestione delle eccezioni. Si tratta di un costrutto del linguaggio piuttosto che di una funzione.
Si aspetta di ricevere un oggetto. Nel caso più semplice, è possibile creare un’istanza della classe interna Exception, come fatto nell’esempio.
Il costruttore della classe prende 2 parametri, un messaggio ed un codice che sarebbero rispettivamente il messaggio ed il codice di errore. Entrambi i parametri sono opzionali.
Infine, sotto il tuo blocco try, è necessario almeno un blocco catch.
Un blocco catch assomiglia a questo:

 

catch (Exception $e)
{
  // gestione dell'eccezione
}

L’oggetto passato al blocco catch è quello passato all’istruzione throw che ha generato l’eccezione.
L’eccezione può essere di qualsiasi tipo, ma è buona norma utilizzare le istanze della classe Exception o casi di eccezioni personalizzate definite dall’utente che ereditano dalla classe Exception.
Quando viene sollevata un’eccezione, PHP cerca un blocco catch corrispondente. Se si dispone di più di un blocco catch, gli oggetti passati a ciascuno dovrebbero essere di tipi diversi in modo che PHP può capire quale blocco catch usare.
Un altro punto da notare è che si può sollevare ulteriori eccezioni all’interno di un blocco catch.

Un semplice esempio di gestione delle eccezioni:

 

try {
  throw new Exception("Si è verifivato un'errore imprevedibile!", 42);
}
catch (Exception $e) {
  echo "Exception ". $e->getCode(). ": ". $e->getMessage()."".
  " in ". $e->getFile(). " on line ". $e->getLine(). "";
}

 

La classe Exception

Come discusso prima il costruttore della classe Exception accetta 2 parametri, il messaggio ed il codice di errore.
In aggiunta al costruttore la classe ha i seguenti metodi:

  • getCode() ->Ritorna il codice passato al costruttore
  • getMessage() -> Ritorna il messaggio passato al costruttore
  • getFile -> Ritorna il full path del file in cui l’eccezione è stata sollevata
  • getLine -> Ritorna il numero di linea in cui l’eccezione viene sollevata
  • getTrace -> Ritorna un array contenente un backtrace dove l’eccezione è stata sollevata
  • getTraceAsString -> Ritorna le stesse info di getTrace formattate come stringa
  • __toString -> Permette di fare un’echo di un oggetto Exception, dando tutte le info dei metodi di sopra. es: echo $e

PS: backtrace mostra quali funzioni erano in esecuzione al momento del sollevamento dell’eccezione.

Eccezioni definite dall’utente

Invece di istanziare e passare un’istanza della classe Exception di base, possiamo passare un oggetto simile.
In molti casi estenderemo la classe Exception per crearne una personalizzata.
Il manuale di PHP fornisce uno scheletro della classe Exception attraverso il quale possiamo capire come estenderla.
Si noti che questo non è il codice vero e proprio ma rappresenta ciò che ci si può aspettare di ereditare:

 

Exception {
  /* Properties */
  protected string $message ;
  protected int $code ;
  protected string $file ;
  protected int $line ;
  /* Methods */
  public __construct ([ string $message = "" [, int $code = 0 [, Exception $previous = NULL ]]] )
  final public string getMessage ( void )
  final public Exception getPrevious ( void )
  final public mixed getCode ( void )
  final public string getFile ( void )
  final public int getLine ( void )
  final public array getTrace ( void )
  final public string getTraceAsString ( void )
  public string __toString ( void )
  final private void __clone ( void )
}

 

Da notare che la maggior parte dei metodi pubblici sono final. Ciò significa che non possono essere sovrascritti.

È possibile creare sottoclassi, ma non è possibile modificare il comportamento dei metodi di base. Notare che invece è possibile eseguire l’override della funzione __toString().
È inoltre possibile aggiungere dei metodi personali. Vediamo un esempio in cui vado e crearmi la mia funzione _toString personalizzata:

 

class myException extends Exception
{
  function __toString()
  {
    return "
Exception ".$this->getCode()." : ".$this->getMessage().""." in ".$this->getFile()." on line ".$this->getLine()."
"; } }

 

Potrò poi tranquillamente usare la mia nuova classe quando voglio generare un’eccezione così:

 

try
{
  throw new myException("A terrible error has occurred", 42);
}
catch (myException $m)
{
  echo $m;
}

 

Vediamo infine un esempio di implementazione in cui definisco tre sottoclassi diverse di Exception, all’interno di un blocco try andrò a generare eccezioni diverse in base all’errore. E’ più semplice intuire il funzionamento leggendo il codice che a parole.
Poniamo che le tre classi che estendono Exception (di cui non sto a scrivere il codice) siano miaException1, miaException2 e miaException2:

try
{
  if ($a = 1)
    throw new miaException1();
  if ($a = 2)
    throw new miaException2()
  if ($a = 2)
    throw new miaException3()

  echo "nessun errore";
}
catch (miaException1() $e1)
{
  echo "

Sto gestendo l'eccezione 1.

";
}
catch (Exception $e)
{
  echo "

Sto gestendo l'eccezione 2 oppure l'eccezione 3.

";
}

 

Da notare infine che ho creato due (invece che tre) cath diversi che vengono eseguiti in base all’oggetto passato.
Se è di tipo miaException1 allora sarà eseguito il primo, mentre negli altri casi il secondo, visto che tutte le classi ereditano da Exception.

2 risposte su “PHP – Gestione delle Eccezioni”

Ciao, c’è una cosa che non ho capito di questo argomento e che nessun blog/sito spiega.

In un contesto di programmazione OOP, il blocco try/catch va posto nel metodo o nell’implementazione dello stesso?

Grazie mille!

No so se ho capito bene la domanda ma direi che la soluzione più logica è lanciare l’eccezione nella dichiarazione del metodo e quindi il try/catch al di fuori, ovvero nel client che chiama il metodo.
Quindi in un’ipotetica applicazione MVC eccezione nel modello e try/catch sul controller.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.