In questo articolo scopriremo le eccezioni PHP da zero. Questi concetti sono utilizzati in molte applicazioni e framework di grandi dimensioni, scalabili e orientati agli oggetti. Approfitta di questa funzionalità del linguaggio per migliorare le tue abilità come sviluppatore di applicazioni web.
Prima di iniziare con tutte le spiegazioni, vorrei prima mostrare un esempio.
Diciamo che vuoi calcolare l'area di un cerchio, per il raggio dato. Questa funzione lo farà:
function circle_area ($ radius) return pi () * $ radius * $ radius;
È molto semplice, tuttavia non controlla se il raggio è un numero valido. Ora lo faremo e lanciamo un'eccezione se il raggio è un numero negativo:
function circle_area ($ radius) // raggio non può essere negativo se ($ radius < 0) throw new Exception('Invalid Radius: ' . $radius); else return pi() * $radius * $radius;
Vediamo cosa succede quando lo chiamiamo con un numero negativo:
$ radius = -2; echo "Raggio cerchio: $ raggio => Area cerchio:". circle_area ($ radius). "\ N"; echo "Un'altra linea";
Lo script si arresta in modo anomalo con il seguente messaggio:
Errore fatale: Eccezione non rilevata 'Eccezione' con messaggio 'Raggio non valido: -2' in C: \ wamp \ www \ test \ test.php: 19 Traccia stack: # 0 C: \ wamp \ www \ test \ test.php (7) : circle_area (-2) # 1 main lanciato C: \ wamp \ www \ test \ test.php in linea 19
Poiché si è trattato di un errore fatale, non è più avvenuta l'esecuzione di codice successiva. Tuttavia, potresti non voler sempre che i tuoi script si fermino ogni volta che si verifica un'eccezione. Fortunatamente, puoi "catturarli" e gestirli.
Questa volta, facciamolo una serie di valori di raggio:
$ radius_array = array (2, -2,5, -3); foreach ($ radius_array come $ radius) try echo "Circle Raggio: $ radius => Circle Area:". circle_area ($ radius). "\ N"; catch (Exception $ e) echo 'Caught Exception:', $ e-> getMessage (), "\ n";
Ora otteniamo questo risultato:
Circle Raggio: 2 => Area cerchio: 12.566370614359 Eccezione catturata: Raggio non valido: -2 Raggio cerchio: 5 => Area cerchio: 78.539816339745 Eccezione catturata: Raggio non valido: -3
Non ci sono più errori e lo script continua a funzionare. È così che trovi le eccezioni.
Le eccezioni sono state utilizzate in altri linguaggi di programmazione orientati agli oggetti per parecchio tempo. È stato inizialmente adottato in PHP con la versione 5.
Per definizione un'eccezione viene "lanciata", quando accade un evento eccezionale. Potrebbe essere semplice come una "divisione per zero" o qualsiasi altro tipo di situazione non valida.
lanciare una nuova eccezione ('Qualche messaggio di errore.');
Questo può sembrare simile ad altri errori di base che hai già visto molte volte. Ma le eccezioni hanno un diverso tipo di meccanismo.
Le eccezioni sono in realtà oggetti e hai la possibilità di "catturarli" ed eseguire determinati codici. Questo viene fatto usando i blocchi 'try-catch':
prova // parte del codice va qui // che potrebbe generare un'eccezione catch (Exception $ e) // il codice qui viene eseguito // se si verifica un'eccezione nel blocco try sopra
Possiamo includere qualsiasi codice all'interno di un blocco 'try'. Il seguente blocco 'catch' viene utilizzato per rilevare eventuali eccezioni che potrebbero essere state lanciate dall'interno del blocco try. Il blocco catch non viene mai eseguito se non ci sono eccezioni. Inoltre, una volta che si verifica un'eccezione, lo script salta immediatamente al blocco catch, senza eseguire alcun altro codice.
Più avanti nell'articolo avremo altri esempi che dovrebbero dimostrare la potenza e la flessibilità dell'uso delle eccezioni invece dei semplici messaggi di errore.
Quando un'eccezione viene lanciata da una funzione o un metodo di classe, va a chi ha chiamato tale funzione o metodo. E continua a farlo fino a quando non raggiunge la cima della pila O viene catturato. Se raggiunge la cima dello stack e non viene mai chiamato, si verificherà un errore irreversibile.
Ad esempio, qui abbiamo una funzione che genera un'eccezione. Chiamiamo questa funzione da una seconda funzione. E infine chiamiamo la seconda funzione dal codice principale, per dimostrare questo effetto bubbling:
function bar () throw new Exception ('Message from bar ().'); function foo () bar (); prova foo (); catch (Exception $ e) echo 'Caught exception:', $ e-> getMessage (), "\ n";
Quindi, quando chiamiamo foo (), tentiamo di rilevare eventuali eccezioni. Anche se foo () non getta uno, ma bar () lo fa, bolle ancora e viene catturato in alto, quindi otteniamo un output che dice: "Caught exception: Message from bar ()."
Dal momento che le eccezioni sono in bolla, possono provenire da qualsiasi luogo. Per semplificare il nostro lavoro, la classe Exception ha metodi che ci consentono di rintracciare l'origine di ogni eccezione.
Vediamo un esempio che coinvolge più file e più classi.
Per prima cosa, abbiamo una classe User e la salviamo come user.php:
class User nome pubblico $; pubblico $ email; funzione pubblica save () $ v = new Validator (); $ V-> validate_email ($ this-> e-mail); // ... save echo "Utente salvato."; ritorna vero;
Utilizza un'altra classe denominata Validator, che inseriamo in validator.php:
class Validator public function validate_email ($ email) if (! filter_var ($ email, FILTER_VALIDATE_EMAIL)) lancia una nuova eccezione ('Email non valida');
Dal nostro codice principale, creeremo un nuovo oggetto Utente, imposteremo il nome e i valori dell'e-mail. Una volta chiamato il metodo save (), utilizzerà la classe Validator per verificare il formato dell'email, che potrebbe restituire un'eccezione:
include ( 'user.php'); include ( 'validator.php'); $ u = nuovo utente (); $ u-> nome = 'pippo'; $ u-> email = '$!% # $% # *'; $ U> save ();
Tuttavia, vorremmo rilevare l'eccezione, quindi non c'è alcun messaggio di errore irreversibile. E questa volta esamineremo le informazioni dettagliate su questa eccezione:
include ( 'user.php'); include ( 'validator.php'); prova $ u = nuovo utente (); $ u-> nome = 'pippo'; $ u-> email = '$!% # $% # *'; $ U> save (); catch (Exception $ e) echo "Message:". $ E-> getMessage (). "\ N \ n"; echo "File:". $ E-> getFile (). "\ N \ n"; echo "Line:". $ E-> getline (). "\ N \ n"; echo "Trace: \ n". $ E-> getTraceAsString (). "\ N \ n";
Il codice sopra produce questo output:
Messaggio: Email non valida File: C: \ wamp \ www \ test \ validator.php Riga: 7 Traccia: # 0 C: \ wamp \ www \ test \ user.php (11): Validator-> validate_email ('$! % # $% # * ') # 1 C: \ wamp \ www \ test \ test.php (12): User-> save () # 2 main
Quindi, senza guardare una singola riga di codice, possiamo dire da dove viene l'eccezione. Possiamo vedere il nome del file, il numero di riga, il messaggio di eccezioni e altro ancora. I dati di traccia mostrano anche le esatte righe di codice che sono state eseguite.
La struttura della classe Exception predefinita è mostrata nel manuale PHP, dove puoi vedere tutti i metodi e i dati con cui viene fornito:
Poiché questo è un concetto orientato agli oggetti ed Eccezione è una classe, possiamo effettivamente estenderla per creare le nostre eccezioni personalizzate.
Ad esempio potresti non voler mostrare tutti i dettagli di un'eccezione all'utente. Invece, è possibile visualizzare un messaggio user-friendly e registrare internamente il messaggio di errore:
// da utilizzare per la classe di problemi del database DatabaseException estende l'eccezione // è possibile aggiungere qualsiasi metodo personalizzato public function log () // registrare questo errore da qualche parte // ... // da utilizzare per la classe di problemi del file system FileException estende Eccezione //…
Abbiamo appena creato due nuovi tipi di eccezioni. E possono avere metodi personalizzati.
Quando rileviamo l'eccezione, possiamo visualizzare un messaggio fisso e chiamare internamente i metodi personalizzati:
function foo () // ... // è successo qualcosa di sbagliato con il database che lanciava una nuova DatabaseException (); prova // metti tutto il tuo codice qui // ... foo (); catch (FileException $ e) die ("Sembra che ci siano problemi con il file system. Siamo spiacenti per l'inconveniente."); catch (DatabaseException $ e) // chiama il nostro nuovo metodo $ e-> log (); // esci con un messaggio die ("Sembra che ci siano problemi con il database. Siamo spiacenti per l'inconveniente."); catch (Exception $ e) echo 'Caught exception:'. $ E-> getMessage (). "\ N";
Questa è la prima volta che guardiamo un esempio con più blocchi catch per un singolo blocco try. In questo modo puoi catturare diversi tipi di eccezioni, in modo che tu possa gestirli diversamente.
In questo caso cattureremo un DatabaseException e solo quel blocco catch verrà eseguito. In questo blog possiamo chiamare i nostri nuovi metodi personalizzati e mostrare all'utente un semplice messaggio.
Si noti che il blocco catch con la classe Exception predefinita deve venire per ultimo, poiché le nostre nuove classi figlie sono considerate ancora tale classe. Ad esempio, "DatabaseException" è considerato anche "Eccezionale", quindi può essere catturato lì se l'ordine è il contrario.
Potresti non voler sempre cercare eccezioni in tutto il tuo codice, avvolgendo tutto in blocchi try-catch. Tuttavia, le eccezioni non rilevate visualizzano un messaggio di errore dettagliato all'utente, che non è ideale anche in un ambiente di produzione.
C'è in realtà un modo per centralizzare la gestione di tutte le eccezioni non rilevate in modo da poter controllare l'output da una singola posizione.
Per questo, utilizzeremo la funzione set_exception_handler ():
set_exception_handler ( 'exception_handler'); function exception_handler ($ e) // messaggio pubblico echo "Qualcosa è andato storto. \ n"; // messaggio semi-nascosto echo "
Come puoi vedere, lo script è stato interrotto dopo la prima eccezione e non ha eseguito il secondo. Questo è il comportamento previsto delle eccezioni non rilevate.
Se si desidera che lo script continui a essere in esecuzione dopo un'eccezione, è necessario utilizzare un blocco try-catch.
Finiremo questo tutorial costruendo una classe di eccezioni MySQL personalizzata che ha alcune funzioni utili e vediamo come possiamo usarla.
la classe MysqlException estende il percorso Exception // al file di log private $ log_file = 'mysql_errors.txt'; funzione pubblica __construct () $ code = mysql_errno (); $ message = mysql_error (); // apre il file di log per l'aggiunta if ($ fp = fopen ($ this-> log_file, 'a')) // costruisce il messaggio di log $ log_msg = date ("[Y-m-d H: i: s]"). "Codice: $ code -". "Messaggio: $ messaggio \ n"; fwrite ($ fp, $ log_msg); fclose ($ fp); // chiama genitore costruttore genitore :: __ costrutto ($ message, $ code);
Potresti notare che inseriamo praticamente tutto il codice nel contructor. Ogni volta che viene lanciata un'eccezione, è come creare un nuovo oggetto, motivo per cui il costruttore viene sempre chiamato per primo. Alla fine del costruttore assicuriamo anche di chiamare il costruttore genitore.
Questa eccezione verrà generata ogni volta che incontriamo un errore MySQL. Quindi recupererà il numero di errore e il messaggio direttamente da mysql, quindi memorizzerà tali informazioni in un file di registro, insieme al timestamp. Nel nostro codice possiamo rilevare questa eccezione, visualizzare un messaggio semplice all'utente e lasciare che la classe di eccezioni gestisca la registrazione per noi.
Ad esempio, proviamo a connetterci a MySQL senza fornire alcuna informazione su utente / password:
prova // tenta di connettersi se (! @mysql_connect ()) lancia la nuova MysqlException; catch (MysqlException $ e) die ("Sembra che ci siano problemi con il database. Siamo spiacenti per l'inconveniente.");
Dobbiamo anteporre l'operatore di soppressione degli errori (@) prima della chiamata a mysql_connect () in modo che non visualizzi l'errore all'utente. Se la funzione fallisce, lanciamo un'eccezione e poi la prendiamo. Solo il nostro messaggio user friendly sarà mostrato al browser.
La classe MysqlException si occupa della registrazione degli errori automaticamente. Quando apri il file di log, troverai questa linea:
[2010-05-05 21:41:23] Codice: 1045 - Messaggio: accesso negato per l'utente 'SYSTEM' @ 'localhost' (utilizzando la password: NO)
Aggiungiamo altro codice al nostro esempio e forniamo anche le informazioni di accesso corrette:
prova la connessione // // dovrebbe funzionare bene se (! @mysql_connect ('localhost', 'root', ")) lancia nuova MysqlException; // seleziona un database (che potrebbe non esistere) if (! mysql_select_db ('my_db') )) throw new MysqlException; // tenta una query (che può avere un errore di sintassi) if (! $ result = mysql_query ("INSERT INTO foo SET bar = '42")) lancia nuova MysqlException; catch ( MysqlException $ e) die ("Sembra che ci siano problemi con il database. Siamo spiacenti per l'inconveniente.");
Se la connessione al database ha esito positivo, ma manca il database denominato "my_db", lo troverai nei registri:
[2010-05-05 21:55:44] Codice: 1049 - Messaggio: database sconosciuto "my_db"
Se il database è presente, ma la query non riesce, a causa di un errore di sintassi, ad esempio, è possibile visualizzare questo nel registro:
[2010-05-05 21:58:26] Codice: 1064 - Messaggio: si è verificato un errore nella sintassi SQL; controlla il manuale che corrisponde alla versione del tuo server MySQL per la sintassi corretta da usare vicino a "42" alla riga 1
Possiamo rendere ancora più pulito l'esempio di codice sopra scrivendo la nostra classe di database, che gestisce la proiezione delle eccezioni. Questa volta userò alcune caratteristiche "magiche" di PHP per costruire questa classe.
Alla fine, vogliamo che il nostro codice principale assomigli a questo:
prova Database :: connect ('localhost', 'root', "); Database :: select_db ('test'); $ result = Database :: query (" INSERT INTO foo SET bar = '42 "); catch (MysqlException $ e) die ("Sembra che ci siano problemi con il database. Siamo spiacenti per l'inconveniente.");
È bello e pulito Non controlliamo gli errori in ogni singola chiamata al database. Questa nuova classe Database ha la responsabilità di generare eccezioni quando si verificano errori. E dal momento che queste eccezioni si gonfiano, vengono catturate dal nostro blocco di cattura alla fine.
Ed ecco la classe di database magica:
class Database // qualsiasi chiamata a funzione statica richiama questa funzione statica pubblica __callStatic ($ name, $ args) // funzione da chiamare $ function = 'mysql_'. $ Name; // la funzione esiste? if (! function_exists ($ function)) // lancia una eccezione regolare per lanciare una nuova Exception ("Funzione mysql non valida: $ function."); // chiama la funzione mysql $ ret = @ call_user_func_array ($ function, $ args); // restituiscono FALSE sugli errori se ($ ret === FALSE) // lancia l'eccezione db lancia nuove MysqlException; // restituisce il valore restituito return $ ret;
Ha solo un metodo e viene richiamato ogni volta che chiamiamo un metodo statico su questa classe. Puoi leggere di più su questo concetto qui: Sovraccarico PHP.
Quindi, quando chiamiamo Database :: connect (), questo codice chiama automaticamente mysql_connect (), passa gli argomenti, verifica la presenza di errori, genera eccezioni quando necessario e restituisce il valore restituito dalla chiamata di funzione. In pratica agisce come un uomo medio e gestisce il lavoro sporco.
Spero ti sia piaciuto questo tutorial e ho imparato da esso. Ora dovresti avere una comprensione migliore di questo argomento. Prova a vedere se puoi utilizzare le eccezioni PHP nel tuo prossimo progetto. Arrivederci alla prossima!