Nello scripting server side in PHP, gli errori possono gestiti tramite eccezioni. Questo approccio, che i programmatori in Java o C++ conosceranno giร molto bene, consente di separare nettamente, giร in fase di sviluppo, la gestione degli errori dalla logica dell’applicativo.
Dato che nella programmazione, gli errori sono inevitabili, diviene necessario creare degli accorgimenti che limitino il piรน possibile le perdite di tempo legate alla ricerca dei frammenti di codice errati velocizzando, contestualmente, la loro risoluzione.
Fino alla versione 4 di PHP, purtroppo, non c’era molto da fare: si scriveva il codice e poi lo si testava, gli errori “venivano fuori” e si andava alla ricerca della riga affetta dall’errore per poi applicare la soluzione adeguata.
Indice
Exception Handling in PHP
Con PHP 5, per fortuna, sono stati introdotti alcuni nuovi strumenti per l’analisi del nostro codice e per la razionalizzazione dei tempi di intervento a carico delle istruzioni mal digitate.
La logica che stร alla base dell’Exception Handling in PHP prende il nome di try (prova), throw (lancia) e catch (cattura), per cui il controllo delle eccezioni emula in parte l’azione svolta dalle istruzioni di controllo o condizionali come if ed else.
Se per esempio salviamo il seguente codice in una pagina chiamata eccezione.php, e lo lanciamo:
<?
throw new Exception('Errore!!!!!!!!');
?>
prevedibilmente, il risultato ottenuto sarร simile all’output riportato qui di seguito:
Fatal error: Uncaught exception 'Exception' with message 'Errore!!!!!!!!' in c:\programmi\php\www\error.php:2 Stack trace: #0 {main} thrown in c:\programmi\php\www\error.php on line 2
Al lancio dello “scriptino” abbiamo due effetti: il primo รจ la notifica di un Uncaught exception (letteralmente: “eccezione non catturata”), il secondo, ben piรน importante ai fini dell’Exception Handling, รจ il fatto che a seguito di questa notifica il resto delle istruzioni contenute nel codice, se presenti, non verranno eseguite.
In pratica, in questo caso l’effetto di un’azione di throwning sul codice PHP puรฒ essere paragonato a quello di una clausola die() che blocca l’esecuzione del listato a seguito di un controllo.
Try, throw e catch delle eccezioni in PHP
L’azione di controllo svolta dalla logica del try, throw e catch prevede quindi due esiti possibili:
- o l’eccezione viene rilevata (catching con esito positivo) e quindi le istruzioni previste nel listato successivo all’errore non vengono escluse dal ciclo di esecuzione stabilito dal sorgente;
- oppure, l’eccezione non viene rilevata (Uncaught exception) e quindi i possibili input previsti vengono abortiti e non producono effetti (o, per meglio dire, non vengono prodotti come effetto).
Per eseguire efficacemente il catching di un’eccezzione รจ possibile racchiudere il codice destinato all’esecuzione all’interno di un blocco in cui รจ prevista la prova e il lancio del listato (un cosiddetto blocco try and catch). All’interno di questo blocco di istruzioni potremo operare una distinzione efficace tra codice privo di errori e codice in grado di produrre notifiche di errore.
Allo scopo di chiarire meglio quanto appena espresso, un esempio pratico puรฒ essere di grande aiuto:
<?
try {
print "Stampa questo codice.";
throw new Exception('<br />Contollo delle eccezioni.');
print "Blocca tutto!!";
}
catch(Exception $var) {
print $var->getMessage();
}
?>
Salviamo il codice appena proposto in una pagina chiamata, ad esempio, eccezione2.php ed eseguiamola. Cosรฌ facendo riceveremo in output la stampa a video delle seguenti stringhe:
Stampa questo codice. Contollo delle eccezioni.
Cosa รจ accaduto? apparentemente non molto, ma in relatร il nostro listato ha eseguito tutta una serie di operazioni che, naturalmente, evidenziano nell’output solo il loro risultato finale.
Innazitutto la prima stringa destinata alla stampa a video (“Stampa questo codice.”) non viene sottoposta a controlli nรจ produce eccezioni, ma rientra comunque nel blocco di try; l’istruzione ad essa correlata verrร eseguita correttamente.
In secondo luogo viene lanciata un’eccezione seguendo la stessa procedura utilizzata nell’esempio precedente. L’eccezione non รจ stata ancora sottoposta ad un’azione di catching e quindi l’istruzione immediatamente sottostante, la stampa a video della stringa “Blocca tutto!!” non viene eseguita.
Viene effettuato il catching dell’eccezione e l’effetto conseguente al lancio di quest’ultima viene passato come valore ad una variabile ($var).
Infine, il metodo getMessage() raccoglie la variabile prodotta dall’azione di catching accettandola come parametro e viene stampata a video la stringa che le รจ stata assegnata come valore.
Try e catch con notifica dell’eccezione
Nel precedente paragrafo abbiamo descritto un primo esempio riguardante la possibilitร di creare un try and catch block all’interno del quale testare gli output derivanti dal sistema di controllo denominato try, throw e catch.
L’esempio precedente non prevede di visualizzare le notifiche di errore al presentarsi di un’eccezione, quindi ora presenteremo del codice destinato ad una funzione esattamente contraria. Salviamo il listato esposto qui sotto in un file chiamato, ad esempio, eccezione3.php:
<?
try {
$n1 = -1000;
$n2 = -2;
if ( $n1 < $b2 )
{
throw new Exception($n1 . " รจ inferiore a " . $n2 . "<br />");
echo "Prova a stamparmi se ci riesci!";
}
}
catch (Exception $excp) {
echo "Alt!! Ho trovato un'eccezione:<br />", $excp;
}
?>
Di seguito, riportiamo per completezza espositiva la stampa a video dell’output conseguente al test del codice appena digitato:
Alt!! Ho trovato un'eccezione: exception 'Exception' with message '-1000 รจ inferiore a -2 ' in c:\programmi\php\www\err.php:7 Stack trace: #0 {main}
Lo script proposto ci riporta a quanto detto all’inizio di questo articolo circa quanto accadeva sino a PHP 4: il limite insito in un sistema come quello stava nell’impossibilitร di poter “specializzare” le operazioni di Exception Handling predefinendo la tipologia di reazione a seconda delle differenti possibilitร di errore.
Nel codice proposto nell’esempio qui sopra abbiamo innanzitutto sottoposto delle istruzioni a try; di seguito abbiamo lanciato, all’interno del blocco try, un’eccezione tramite throw e questo ha determinato l’impossibilitร di eseguire le ulteriori istruzioni poste all’interno dello stesso blocco try.
L’eccezione รจ stata quindi istanziata quale oggetto appartenente alla classe precedentemente definita, cioรจ Exception. L’istanza, conferendo delle proprietร all’oggetto lo ha reso riutilizzabile, infatti, lo ritroviamo al di fuori del blocco di try dove diviene argomento di un’istruzione e non ne blocca l’esecuzione.
Variabili e metodi per le eccezioni in PHP
In questo articolo descriveremo le variabili e i metodi che entrano in gioco nelle azioni di Exception Handling, entrambi sono elementi costitutivi รจ nativi della classe Exception, vera protagonista della gestione degli errori tramite eccezioni.
La variabili
Per quanto riguarda le variabili, vanno presi in considerazione essenzialmente tre voci:
- Exception :: message: il messaggio di errore che verrร passato come argomento al costruttore della classe.
- Exception :: line: il punto esatto del blocco di codice in cui viene generato l’errore.
- Exception :: file:il nome del file PHP in cui a origine l’errore gestito tramite eccezione.
Le tre variabili appena descritte sono “protette”, non potranno quindi essere riscritte e ogni tentativo di modifica a loro carico non farร altro che generare la notifica di un errore.
I metodi
Passiamo ora ai metodi. Questi ultimi sono pubblici e quindi accessibili in tutto il contesto appartenente alla classe in cui viene istanziato l’oggetto. Per la precisione possiamo distinguere 5 diversi metodi:
- Exception :: getMessage(): lo abbiamo descritto in precedenza; esso รจ destinato a raccogliere come parametro la notifica di errore che viene generata dal controllo delle eccezioni. In pratica reinvia il messagio di errore come parametro al costruttore della classe di riferimento.
- Exception :: getLine(): รจ il metodo che permette il reinvio alla riga di codice in cui si verifica l’errore.
- Exception :: getTrace(): metodo che reinvia ad una tabella associtiva riguardante le caratteristiche dell’errore.
- Exception :: getTraceAsString(): metodo che svolge una funzione similare all’Exception :: getTrace() ma crea una stringa con lo stesso contenuto di informazioni.
Il metodo Exception :: getTrace()
Exception :: getTrace() si presenta come il metodo piรน complesso in quanto contiene differenti tipi di informazioni riguardanti l’entitร dell’errore gestito. All’interno di quest’ultimo metodo rileviamo 6 differenti elementi costitutivi che potremo riassumere nell’elenco seguente:
- file: il documento in cui si verifica l’errore.
- line: la riga di codice in cui si verifica l’errore.
- function: la funzione coinvolta nell’errore.
- class: la classe coinvolta nell’errore.
- type: il modo in cui viene richiamato il metodo che potrebbe essere statico o dinamico.
- args: gli argomenti passati al metodo raccolti in una tabella associativa.
Una classe per la gestione delle eccezioni
Dopo la nostra breve discussione sulle dinamiche e le procedure da adottare per la gestione degli errori tramite eccezioni in PHP 5, cercheremo di chiarire definitivamente le idee al lettore presentandogli un esempio pratico riguardante l’utilizzo del sistema try, throw e catch.
Nello specifico creeremo una classe da poter impiegare in un’operazione abbastanza frequente nello sviluppo di applicazioni in PHP: una funzione per l’apertura di un file in lettura.
Chiameremo la nostra funzione personalizzata ApriScatole(), mentre la classe di appartenenza prenderร il nome di provaEccezione. Di seguito riportiamo il listato completo di funzione e utilizzo pratico della stessa:
<?
//definizione della classe
class provaEccezione {
//creiamo la funzione
public function ApriScatole($file) {
if(!@fopen($file, 'r'))
{
//stabiliamo le modalitร di gestione dell'errore
throw new Exception ('Il ' . $file . 'non si apre!!!');
}
}
}
//istanza
$obj = new provaEccezione;
//tentiamo di aprire un file inesistente
try {
$obj -> ApriScatole('/percorso/file_inesistente.txt');
//se il file esiste stampo a video una conferma
echo 'Ho aperto il file!';
}
//cathing dell'eccezione
catch (Exception $excp) {
echo $excp -> getMessage();
}
?>
Basterร il semplice test dello script appena presentato per osservare gli effetti della gestione dell’errore.
In pratica non abbiamo fatto altro che definire una classe all’interno della quale รจ stata creata una funzione che controlla l’effettiva apertura in lettura di un file. Se il file passato come argomento non viene aperto, allora l’errore viene gestito secondo le modalitร previste nella fase di throw.
Per testare la funzione abbiamo proceduto con l’istanza di un oggetto nel tentativo di aprire un file inesistente utilizzando la funzione appena creata, ma l’operazione porterร logicamente ad un errore la cui notifica verrร raccolta tramite catch e visualizzata tramite il metodo getMessage().