Le eccezioni sono gli strumenti della programmazione orientata agli oggetti, che fornisce un modo elegante per lanciare e gestire (trattare) gli errori delle applicazioni.
Un'eccezione viene prima lanciata (thrown
), trattata (try
) e catturata (catch
). Solo il lancio è obbligatorio.
Prima della comparsa delle eccezioni, la gestione degli errori nella programmazione era molto complicata perché dovevamo fare affidamento sui valori di ritorno delle funzioni e catturarli a modo nostro e comportarci di conseguenza.
Infatti, le funzioni stesse non applicano la gestione degli errori, il che può portare a problemi fatali, ma David ha scritto su questo in Programmers don't ignore errors.
Un esempio di gestione degli errori dimenticati:
// passando da disco a discocopy('c:/oldfile', 'd:/newfile');unlink('c:/oldfile');// se la prima operazione fallisce, il file viene irrimediabilmente cancellato
Questo perché il modo corretto di gestire l'output della funzione copy()
è di non continuare e lanciare un errore. Nel caso delle buone vecchie funzioni, potrebbe essere così:
function backup(): bool{if (copy('c:/oldfile', 'd:/newfile')) {return unlink('c:/oldfile');}return false;}
La nostra funzione backup()
restituirà true
solo se la funzione copy()
non ha fallito e la funzione unlink()
ha restituito true
. Altrimenti, restituirà false
.
Ma questo è ora sicuro per l'applicazione? Non lo è! Perché ora dobbiamo trattare l'output della funzione backup()
nel punto in cui la chiamiamo, e se fallisce, non sapremo nemmeno perché. In breve, restituirà false
e dobbiamo rilevare l'errore da soli in qualche modo. Credo che in questo caso sia un bene vedere che i programmatori spesso rinunciano alla gestione degli errori, o semplicemente si dimenticano di gestire qualcosa e l'applicazione lancia errori difficili da rilevare a causa di questo.
La soluzione a questo problema è usare eccezioni che forzano il trattamento, e se non vengono trattate, l'applicazione si blocca completamente e si scopre sempre il perché.
In PHP, un'eccezione è un tipo speciale di interfaccia implementata dalla classe nativa Exception
che useremo.
Se l'elaborazione di qualche parte del programma fallisce, si lancia semplicemente un'eccezione che descrive il problema:
if (copy('c:/oldfile', 'd:/newfile') === false) {throw new \Exception('Impossibile copiare il file "oldfile".');}
Il lancio di un'eccezione è fatto con la parola chiave throw
, seguita dalla creazione di un'istanza della classe con l'eccezione. Possiamo anche ottenere un'istanza in altri modi (per esempio, passandola da una variabile), e la semplice creazione di un'istanza di eccezione non ne causa il lancio.
Il primo argomento del costruttore della classe Exception
accetta il testo dell'eccezione, che dovrebbe spiegare in modo conciso cosa è appena successo. È buona pratica includere anche informazioni sull'operazione che viene eseguita e un riferimento ai dati. Per esempio, se una copia di un file è fallita, è buona pratica passare il nome del file. Se l'esecuzione della query SQL fallisce, passiamo di nuovo la query in esecuzione. Questo ci aiuterà molto più tardi quando gestiremo gli errori, perché possiamo vedere esattamente qual è il problema.
Per esempio, abbiamo una funzione backup()
che fa il backup dei dati e può lanciare un paio di errori:
function backup(): void{if (copy('c:/oldfile', 'd:/newfile')) {if (unlink('c:/oldfile') === false) {throw new \Exception('Non posso rimuovere il vecchio file.');}}throw new \Exception('Non è possibile copiare i file di backup.');}
Notate che la funzione non restituisce alcun output, e noi specifichiamo il tipo void
nella definizione. La funzione non ha bisogno di restituire nulla, perché il successo è considerato uno stato in cui non viene lanciato nessun errore e non abbiamo bisogno di trattare uno scenario positivo.
Se dovessimo usare la funzione in un'applicazione senza trattamento, per esempio, come segue:
echo 'I file di backup...';backup();echo 'Backup completato.';
Questo è il modo normale in cui funziona. Tuttavia, se si verifica un errore, lo script terminerà automaticamente e il testo dell'eccezione sarà visualizzato sull'output. È importante che non continui ad eseguire il codice e sappiamo che non ci sarà corruzione dei dati.
Se vogliamo continuare l'esecuzione, dobbiamo pulire l'errore, cosa che facciamo usando i costrutti try
e catch
:
echo 'I file di backup...';try {backup();} catch (\Exception $e) {echo 'Backup fallito:' . $e->getMessage();}echo 'Backup completato.';
Se viene lanciata un'eccezione, il codice nell'area catch()
(che accetta l'eccezione se corrisponde al suo tipo di dati) viene chiamato e il codice interno viene eseguito.
Otteniamo sempre un'istanza della classe delle eccezioni, che può essere usata, per esempio, per visualizzare un messaggio di errore, che è gestito dal metodo getMessage()
. È anche utile conoscere il metodo getFile()
, che restituisce il percorso su disco del file che contiene l'errore, getCode()
, che restituisce il codice di stato dell'errore, e getLine()
, che restituisce il numero di linea dove è stata lanciata l'eccezione.
Oltre all'eccezione di base \Exception
, PHP include altri tipi di eccezione predefiniti che sono adatti a diversi casi d'uso.
Tipo di dati | Spiegazione |
---|---|
LogicException |
Errore logico, prevedibile nella progettazione del programma |
BadFunctionCallException |
Errore di chiamata di funzione; funzione non trovata; chiamata non permessa |
BadMethodCallException |
Errore nella chiamata del metodo |
InvalidArgumentException |
Argomento errato (non valido) passato alla funzione o al metodo |
OutOfRangeException |
Valore fuori dall'intervallo della matrice o dell'insieme |
LengthException |
Il valore supera la lunghezza consentita |
DomainException |
Il valore non rientra nel dominio o nell'intervallo richiesto |
RuntimeException |
Errore rilevabile solo in fase di esecuzione (per esempio, mancata scrittura di un file) |
OverflowException |
Overflow del buffer o delle operazioni aritmetiche, spesso causato dall'elaborazione di più dati del previsto |
UnderflowException |
Underflow di un buffer o di un'operazione aritmetica, sono stati passati meno dati del previsto |
OutOfBoundsException |
Indice fuori dall'intervallo della matrice o dell'insieme |
RangeException |
Valore non compreso nell'intervallo richiesto |
UnexpectedValueException |
Valore inaspettato (ad esempio il valore di ritorno di una funzione) |
Le eccezioni LogicException
e RuntimeException
dovrebbero essere prevenute da una corretta progettazione del programma. Personalmente, li uso solo per situazioni eccezionali, come la mancata scrittura di un file e la comunicazione con un servizio esterno.
Raccomando di non catturare affatto la RuntimeException
e lasciare che l'applicazione fallisca. Questo è di solito un problema serio che dovrebbe essere segnalato il prima possibile.
Jan Barášek Více o autorovi
Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.
Rád vám pomůžu:
Články píše Jan Barášek © 2009-2024 | Kontakt | Mapa webu
Status | Aktualizováno: ... | it