Capire le Eccezioni PHP
In PHP, le eccezioni gestiscono errori imprevisti e problemi a runtime. Scopri come usare throw, catch, finally e classi personalizzate.
Un'eccezione è un oggetto che rappresenta un errore o una condizione inaspettata che interrompe il normale flusso del programma. Invece di restituire un codice di errore che il chiamante potrebbe dimenticare di verificare, il codice "lancia" un'eccezione; il runtime risale lo stack delle chiamate finché non trova un blocco catch corrispondente. Se nessun blocco la intercetta, lo script si interrompe con un errore fatale.
Questo capitolo spiega come lanciare e intercettare le eccezioni, i metodi esposti da ogni eccezione (getMessage(), getCode(), getLine(), getFile()), il blocco finally, i blocchi catch multipli, le classi di eccezione personalizzate e la differenza tra Exception e Error.
Cos'è un'Eccezione PHP?
Un'eccezione PHP è un oggetto che discende dalla classe built-in Exception (o, più in generale, dall'interfaccia Throwable). Quando qualcosa va storto — un file mancante, un argomento non valido, una connessione al database fallita — si crea uno di questi oggetti e lo si lancia con throw. Il lancio interrompe immediatamente il percorso di esecuzione corrente e passa il controllo al gestore più vicino.
Usa un'eccezione quando una funzione non può continuare in modo significativo e il chiamante è il posto giusto per decidere cosa fare dopo. Non usarle per il normale flusso di controllo (una normale ricerca "utente non trovato" è meglio espressa con un valore di ritorno).
Lanciare un'Eccezione
La parola chiave throw solleva un'eccezione, seguita da una nuova istanza di una classe di eccezione. Il costruttore accetta un messaggio opzionale, un codice intero e un'eccezione precedente (per il concatenamento):
<?php
function divide(int $a, int $b): float
{
if ($b === 0) {
throw new InvalidArgumentException('Division by zero is not allowed.');
}
return $a / $b;
}
try {
echo divide(10, 0);
} catch (InvalidArgumentException $e) {
echo 'Error: ' . $e->getMessage();
}
?>Output:
Error: Division by zero is not allowed.Il codice all'interno di try viene eseguito normalmente finché non si attiva throw. Da quel momento in poi il resto del blocco try viene saltato e viene eseguito il blocco catch corrispondente.
Gestire le Eccezioni con try / catch
Si racchiude il codice che potrebbe fallire in un blocco try e si gestisce il fallimento in un blocco catch. La variabile in catch (qui $e) contiene l'oggetto eccezione, che espone diversi metodi di sola lettura:
| Metodo | Restituisce |
|---|---|
getMessage() | Il messaggio leggibile dall'utente |
getCode() | Il codice intero passato al costruttore |
getLine() | La riga dove è stata lanciata l'eccezione |
getFile() | Il file in cui è stata lanciata |
getPrevious() | L'eccezione "precedente" concatenata, se presente |
getTraceAsString() | Lo stack trace come stringa |
<?php
try {
throw new Exception('Something failed', 42);
} catch (Exception $e) {
echo 'Message: ' . $e->getMessage() . PHP_EOL;
echo 'Code: ' . $e->getCode() . PHP_EOL;
}
?>Output:
Message: Something failed
Code: 42Intercettare Più Tipi di Eccezione
Un singolo blocco try può avere più blocchi catch. PHP li verifica dall'alto verso il basso ed esegue il primo il cui tipo corrisponde. Da PHP 7.1 è possibile intercettare più tipi non correlati in un unico blocco usando l'operatore pipe (|):
<?php
try {
throw new RuntimeException('Network is down');
} catch (InvalidArgumentException $e) {
echo 'Bad argument: ' . $e->getMessage();
} catch (RuntimeException | LogicException $e) {
echo 'Runtime/logic problem: ' . $e->getMessage();
}
?>Output:
Runtime/logic problem: Network is downL'ordine è importante: elenca i tipi di eccezione più specifici prima delle loro classi padre, altrimenti il catch generico intercetta tutto per primo.
Il Blocco finally
Il blocco finally è opzionale ma utile. Il suo codice viene sempre eseguito — che venga lanciata o meno un'eccezione, e anche se il blocco try o catch esegue un return. Questo lo rende il posto giusto per operazioni di pulizia come la chiusura di un file o il rilascio di un lock:
<?php
try {
echo 'Open resource' . PHP_EOL;
throw new Exception('Boom');
} catch (Exception $e) {
echo 'Caught: ' . $e->getMessage() . PHP_EOL;
} finally {
echo 'Cleanup always runs' . PHP_EOL;
}
?>Output:
Open resource
Caught: Boom
Cleanup always runsClassi di Eccezione Personalizzate
Oltre ai tipi built-in puoi definire le tue classi di eccezione estendendo Exception. Una classe personalizzata ti permette di portare dati aggiuntivi (come un valore che ha causato il fallimento) e consente ai chiamanti di intercettare il tuo tipo di errore specifico senza accidentalmente intercettare quelli non correlati:
<?php
class InsufficientFundsException extends Exception
{
private float $shortfall;
public function __construct(float $shortfall)
{
$this->shortfall = $shortfall;
parent::__construct("Short by $shortfall");
}
public function getShortfall(): float
{
return $this->shortfall;
}
}
try {
throw new InsufficientFundsException(25.5);
} catch (InsufficientFundsException $e) {
echo $e->getMessage() . PHP_EOL;
echo 'Need ' . $e->getShortfall() . ' more.';
}
?>Output:
Short by 25.5
Need 25.5 more.PHP fornisce anche una famiglia di eccezioni SPL già pronte — InvalidArgumentException, RuntimeException, LengthException e altre — quindi spesso non è necessario inventarne di proprie.
Exception vs. Error
Da PHP 7, i fallimenti interni del motore (come un errore di tipo o la chiamata a un metodo non definito) vengono lanciati come oggetti Error, non Exception. Entrambi implementano l'interfaccia Throwable. Un semplice catch (Exception $e) non intercetterà un Error. Per gestire entrambi, intercetta l'interfaccia:
<?php
try {
$result = 10 % 0; // throws a DivisionByZeroError
} catch (Throwable $e) {
echo get_class($e) . ': ' . $e->getMessage();
}
?>Output:
DivisionByZeroError: Modulo by zeroCome regola generale, riserva Exception per i problemi da cui la tua applicazione può riprendersi, e lascia che Error rappresenti i bug da correggere piuttosto che da intercettare.
Argomenti Correlati
- Errori PHP — la differenza tra errori ed eccezioni.
- Istruzione PHP
try— uno sguardo approfondito al costruttotry. set_exception_handler()— un fallback globale per le eccezioni non intercettate.- Classi e Oggetti PHP — necessari per costruire classi di eccezione personalizzate.
- Funzioni PHP — dove le eccezioni vengono lanciate più spesso.
Conclusione
Le eccezioni offrono a PHP un modo strutturato per gestire i fallimenti: una funzione lancia con throw quando non può continuare, e il chiamante intercetta con catch per recuperare, registrare o rilanciare. Combina try, catch e finally per separare il percorso normale dalla gestione degli errori e dalla pulizia, usa classi personalizzate per modellare i fallimenti del tuo dominio e ricorda che i problemi a livello di motore arrivano come Error (intercettabili tramite Throwable). Applicare questi pattern nei tuoi progetti renderà il codice molto più robusto.