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().