În acest articol vom afla despre excepțiile PHP de la început. Aceste concepte sunt utilizate în multe aplicații și cadre mari, scalabile și orientate spre obiecte. Profitați de această caracteristică lingvistică pentru a vă îmbunătăți abilitățile ca dezvoltator de aplicații web.
Înainte de a începe cu toate explicațiile, aș dori să arăt mai întâi un exemplu.
Să presupunem că doriți să calculați aria unui cerc, pe raza dată. Această funcție va face acest lucru:
funcția circle_area (raza $) returnați pi () * raza $ * raza $;
Este foarte simplu, însă nu verifică dacă raza este un număr valid. Acum o să facem acest lucru și aruncăm o excepție dacă raza este un număr negativ:
funcția cercul_area (raza $) // raza nu poate fi negativă dacă (raza $ < 0) throw new Exception('Invalid Radius: ' . $radius); else return pi() * $radius * $radius;
Să vedem ce se întâmplă atunci când o numim cu un număr negativ:
$ radius = -2; ecou "Raza cercului: $ radius => Zona cercului:". cerc_area (raza $). "\ N"; echo "O altă linie";
Scriptul se blochează cu următorul mesaj:
Eroare fatala: Exemplu de excepție "Excepție" cu mesajul "Radius nevalid: -2" în C: \ wamp \ www \ test \ test.php: 19 Trasare stivă: # 0 C: \ wamp \ : circle_area (-2) # 1 main aruncat în C: \ wamp \ www \ test \ test.php pe net 19
Deoarece a fost o eroare fatală, nu sa mai produs o execuție de cod după aceea. Cu toate acestea, s-ar putea să nu vreți ca scenariile dvs. să se oprească ori de câte ori se întâmplă o excepție. Din fericire, îi poți "prinde" și să le iei.
De data aceasta, hai să facem o gamă de valori de rază:
$ radius_array = array (2, -2,5, -3); foreach ($ radius_array ca rază de $) try echo "Circle Radius: $ radius => Zona cercului:". cerc_area (raza $). "\ N"; captură (Excepție $ e) echo 'Excepție capturată:', $ e-> getMessage (), "\ n";
Acum obținem această ieșire:
Circle Radius: 2 => Suprafață cerc: 12.566370614359 Excepție capturată: Radius invalid: -2 Circulară: 5 => Zonă cerc: 78.539816339745 Excepție capturată: Invalid Radius: -3
Nu mai există erori și scriptul continuă să ruleze. Așa câștigați excepțiile.
Excepții au fost în jur de alte limbi de programare orientate obiect de ceva timp. Acesta a fost inițial adoptat în PHP cu versiunea 5.
Prin definiție, o excepție este "aruncată", când se produce un eveniment excepțional. Acest lucru ar putea fi la fel de simplu ca o "împărțire la zero" sau orice alt tip de situație nevalidă.
aruncați o nouă excepție ("Un mesaj de eroare");
Acest lucru poate părea similar cu alte erori de bază pe care le-ați văzut deja de mai multe ori. Dar excepțiile au un mecanism diferit.
Excepțiile sunt de fapt obiecte și aveți opțiunea de a le "prinde" și de a executa anumite coduri. Acest lucru se face prin utilizarea blocurilor "try-catch":
încercați // un cod merge aici // care ar putea arunca o excepție captură (Excepție $ e) // codul aici este executat doar dacă excepția sa produs în blocul de încercare de mai sus
Putem introduce orice cod într-un bloc "try". Următorul bloc "captură" este utilizat pentru capturarea oricărei excepții care ar putea fi aruncată din blocul de încercare. Blocajul de captură nu se execută niciodată dacă nu există excepții. De asemenea, odată ce se întâmplă o excepție, scriptul sare imediat la blocul de captură, fără a executa niciun alt cod.
Mai departe, în articol vom avea mai multe exemple care ar trebui să demonstreze puterea și flexibilitatea utilizării excepțiilor în locul mesajelor simple de eroare.
Atunci când o excepție este aruncată dintr-o funcție sau dintr-o metodă de clasă, aceasta se adresează celor care au apelat la această funcție sau la o metodă. Și continuă să facă acest lucru până când ajunge în partea superioară a stivei SAU este prins. Dacă ajunge în partea de sus a stivei și nu este chemat niciodată, veți primi o eroare fatală.
De exemplu, aici avem o funcție care aruncă o excepție. Noi numim această funcție dintr-o a doua funcție. Și în cele din urmă numim a doua funcție din codul principal, pentru a demonstra acest efect bubbling:
bara de funcții () arunca o nouă excepție ("Mesaj din bar ()"); funcția foo () bar (); încercați foo (); captură (Excepție $ e) echo "Excepție capturată: ', $ e-> getMessage ()," \ n ";
Deci, atunci când suntem foo (), încercăm să prindem orice posibilă excepție. Chiar dacă foo () nu aruncă unul, dar bar () nu, acesta încă bubbles și este prins în partea de sus, așa că vom obține o ieșire spunând: "Excepție capturată: Mesaj de la bar ()".
Din moment ce excepțiile fac bubble, pot veni de oriunde. Pentru a face munca mai ușoară, clasa Excepție are metode care ne permit să urmărim sursa fiecărei excepții.
Să vedem un exemplu care implică mai multe fișiere și mai multe clase.
În primul rând, avem o clasă User și o salvăm ca user.php:
utilizator de clasă public $ name; public $ email; funcția publică salvați () $ v = Validator nou (); $ V-> validate_email ($ this-> e-mail); // ... salvează ecoul "Utilizatorul a salvat."; return true;
Utilizează o altă clasă numită Validator, pe care o punem în validator.php:
Validator de clasă funcția publică validate_email ($ email) if (! filter_var ($ email, FILTER_VALIDATE_EMAIL)) arunca o nouă excepție ("Emailul este nevalid");
Din codul nostru principal, vom crea un nou obiect utilizator, vom seta valorile numelui și e-mailului. Odată ce vom apela metoda save (), vom folosi clasa Validator pentru verificarea formatului de e-mail, care ar putea reveni la o excepție:
includ ( 'user.php'); includ ( 'validator.php'); $ u = utilizator nou (); $ u-> nume = 'foo'; $ u-> email = '$!% # $% # *'; $ U-> Salvare ();
Cu toate acestea, am dori să prindem excepția, deci nu există un mesaj de eroare fatal. Și de data aceasta vom examina detaliile despre această excepție:
includ ( 'user.php'); includ ( 'validator.php'); încercați $ u = nou utilizator (); $ u-> nume = 'foo'; $ u-> email = '$!% # $% # *'; $ U-> Salvare (); captură (Excepție $ e) ecou "Mesaj:". $ E> getMessage (). "\ N \ n"; echo "Fișier:". $ E> getfile (). "\ N \ n"; ecou "Linie:". $ E> getline (). "\ N \ n"; echo "Trace: \ n". $ E> getTraceAsString (). "\ N \ n";
Codul de mai sus produce această ieșire:
Mesaj: E-mailul nu este valid Fișierul: C: \ wamp \ www \ test \ validator.php Linia: 7 Trace: # 0 C: \ wamp \ www \ test \ user.php (11): Validator-> validate_email (# 12): User-> save () # 2 main
Deci, fără să ne uităm la o singură linie de cod, putem spune de unde provine excepția. Putem vedea numele fișierului, numărul liniei, mesajul de excepții și multe altele. Datele de urmărire arată chiar și liniile exacte ale codului care au fost executate.
Structura clasei Excepție implicită este prezentată în manualul PHP, unde puteți vedea toate metodele și datele pe care le conține:
Deoarece acesta este un concept orientat pe obiecte și Excepția este o clasă, putem extinde de fapt pentru a crea propriile noastre excepții personalizate.
De exemplu, este posibil să nu doriți să afișați toate detaliile unei excepții de la utilizator. În schimb, puteți afișa un mesaj ușor de utilizat și înregistrați intern mesajul de eroare:
// pentru a fi utilizate pentru probleme de baze de date clasa DatabaseException extinde Exceptie // puteți adăuga orice metodă personalizată log public funcția () // log această eroare undeva // ... // să fie utilizat pentru clasa de fișiere probleme FileException se extinde Excepție //…
Tocmai am creat două noi tipuri de excepții. Și pot avea metode personalizate.
Când vom prinde excepția, vom putea afișa un mesaj fix și vom apela metodele personalizate intern:
funcția foo () // ... // sa întâmplat ceva greșit cu baza de date arunca o nouă bază de date DatabaseException (); încercați // puneți tot codul aici // ... foo (); catch (FileException $ e) mor ("Se pare că avem probleme de sistem de fișiere. Ne pare rău pentru neplăcerile"); captură (DatabaseException $ e) // apelarea noii metode $ e-> log (); // ieșiți cu un mesaj de morți ("Se pare că avem probleme de baze de date. Ne pare rău pentru inconveniente."); captură (Excepție $ e) echo 'Excepție capturată:'. $ E> getMessage (). "\ N";
Aceasta este prima dată când ne uităm la un exemplu cu mai multe blocuri de captură pentru un singur bloc de încercare. Acesta este modul în care puteți prinde diferite tipuri de Excepții, astfel încât să le puteți trata în mod diferit.
În acest caz, vom prinde o DatabaseException și numai blocul de captură va fi executat. În acest blog ne putem suna noile metode personalizate și vom afișa un mesaj simplu utilizatorului.
Rețineți că blocul de captură cu clasa de excepție implicită trebuie să fie ultimul, deoarece noile clase de copii sunt, de asemenea, încă considerate ca fiind clase. De exemplu, "DatabaseException" este, de asemenea, considerată "Excepție", astfel încât poate fi prinsă acolo dacă ordinul este invers.
Este posibil să nu doriți întotdeauna să căutați excepții în tot codul dvs., prin împachetarea a tot ceea ce se întâmplă în blocurile de încercare. Cu toate acestea, excepțiile neobișnuite afișează un mesaj de eroare detaliat utilizatorului, care, de asemenea, nu este ideal într-un mediu de producție.
Există, de fapt, o modalitate de a centraliza manipularea tuturor excepțiilor neafectate, astfel încât să puteți controla producția dintr-o singură locație.
Pentru aceasta, vom folosi funcția set_exception_handler ():
set_exception_handler ( 'exception_handler'); funcția exception_handler ($ e) // mesajul public echo "Ceva a mers prost. \ n"; // mesajul semi-ascuns ecou "
După cum puteți vedea scriptul avortat după prima excepție și nu a executat al doilea. Acesta este comportamentul așteptat al excepțiilor neclare.
Dacă doriți ca scriptul dvs. să ruleze în continuare după o excepție, va trebui să utilizați în schimb un bloc de încercare.
Vom finaliza acest tutorial construind o clasă excepțională MySQL care are câteva caracteristici utile și vom vedea cum o putem folosi.
clasa MysqlException extinde Excepție // cale către fișierul jurnal privat $ log_file = 'mysql_errors.txt'; funcția publică __construct () $ code = mysql_errno (); $ message = mysql_error (); // deschideți fișierul jurnal pentru a adăuga dacă $ fp = fopen ($ this-> log_file, 'a')) // construi mesajul jurnal $ log_msg = data ("[Y-m-d H: i: s]"). "Cod: $ code -". "Mesaj: $ message \ n"; fwrite ($ fp, $ log_msg); fclose ($ fp); // apela parent constructor parent :: __ construct ($ message, $ code);
S-ar putea să observați că punem aproape tot codul în contructor. Ori de câte ori o excepție este aruncată, este ca și cum ați crea un obiect nou, motiv pentru care constructorul este întotdeauna chemat primul. La finalul constructorului, asigurați-vă că sunați la constructorul părinte.
Această excepție va fi aruncată ori de câte ori întâlnim o eroare MySQL. Acesta va prelua apoi numărul de eroare și mesajul direct din mysql și apoi va stoca acea informație într-un fișier jurnal împreună cu marcajul de timp. În codul nostru putem să capturăm această excepție, să afișăm un mesaj simplu utilizatorului și să lăsăm clasa excepțională să se ocupe de logare pentru noi.
De exemplu, să încercăm să ne conectăm la MySQL fără a furniza informații despre utilizatori / parole:
încercați // încercați să vă conectați dacă (! @mysql_connect ()) arunca noua MysqlException; captură (MysqlException $ e) muri ("Se pare că avem probleme de baze de date. Ne pare rău pentru inconveniente.");
Trebuie să prefixăm operatorul de suprimare a erorilor (@) înainte de apelul mysql_connect (), astfel încât acesta să nu afișeze eroarea pentru utilizator. Dacă funcția nu reușește, aruncăm o excepție și apoi o prindem. Numai mesajul nostru ușor de utilizat va fi afișat browserului.
Clasa MysqlException se ocupă automat de înregistrarea erorilor. Când deschideți fișierul jurnal, veți găsi această linie:
[2010-05-05 21:41:23] Cod: 1045 - Mesaj: Accesul a fost refuzat pentru utilizator 'SYSTEM' @ 'localhost' (folosind parola: NU)
Să adăugăm mai multe coduri la exemplul nostru și să furnizăm, de asemenea, o informație corectă de autentificare:
mysql_select_db ('my_db', 'mysql_select_db' ('my_db', 'mysql_select_db' ('my_db' )) arunca noua MysqlException; // incearca o interogare (care poate avea o eroare de sintaxa) daca (! $ result = mysql_query ("INSERT INTO foo SET bar = '42")) MysqlException $ e) mor ("Se pare că avem probleme de baze de date. Ne pare rău pentru inconveniente.");
Dacă conexiunea bazei de date reușește, dar baza de date numită "my_db" lipsește, veți găsi aceasta în jurnale:
[2010-05-05 21:55:44] Cod: 1049 - Mesaj: baza de date necunoscută "my_db"
Dacă baza de date există, dar interogarea eșuează, din cauza unei erori de sintaxă, de exemplu, este posibil să vedeți acest lucru în jurnal:
[2010-05-05 21:58:26] Cod: 1064 - Mesaj: Aveți o eroare în sintaxa SQL; verificați manualul care corespunde versiunii dvs. de server MySQL pentru a utiliza sintaxa potrivită în dreptul liniei "42" la linia 1
Putem face exemplul de cod de mai sus chiar mai curat scriind propria clasă de baze de date, care gestionează aruncarea excepțiilor. De data aceasta voi folosi câteva funcții "magice" ale PHP pentru a construi această clasă.
În final, dorim ca codul nostru principal să arate astfel:
încercați Database :: connect ('localhost', 'root', "); Database :: select_db ('test'); $ result = Database :: interogare (" INSERT INTO foo SET bar = '42 " (MysqlException $ e) mor ("Se pare că avem probleme de baze de date. Ne pare rău pentru inconveniente.");
Este frumos și curat. Nu verificăm dacă există erori la fiecare apel de bază de date. Această nouă clasă de baze de date are responsabilitatea de a arunca excepții atunci când au loc erori. Iar din moment ce aceste excepții se balonează, sunt prinse de blocul nostru de captură la sfârșit.
Și aici este clasa magică Database:
Baza de date a bazei de date // orice apel funcțional static invocă această funcție statică publică __callStatic ($ name, $ args) // funcția de a fi numită $ function = 'mysql_'. $ nume; // funcția există? dacă (! function_exists ($ function)) // aruncați o excepție regulată arunca o excepție nouă ("funcția mysql invalid: $ function"); // apela funcția mysql $ ret = @call_user_func_array ($ function, $ args); // returneaza FALSE pe erori daca ($ ret === FALSE) // arunca exceptia db arunca noua MysqlException; // returnează valoarea returnată return $ ret;
Are doar o singură metodă și se invocă ori de câte ori numim o metodă statică în această clasă. Puteți citi mai multe despre acest concept aici: PHP Overloading.
Deci, când numim Database :: connect (), acest cod invocă automat mysql_connect (), trece argumentele, verifică erorile, aruncă excepții atunci când este necesar și returnează valoarea returnată din apelul pentru funcții. Practic se comportă ca un om din mijloc și se ocupă de munca murdară.
Sper că v-ați bucurat de acest tutorial și ați învățat de la el. Acum ar trebui să înțelegeți mai bine acest subiect. Încercați să vedeți dacă puteți utiliza excepțiile PHP în următorul proiect. Ne vedem data viitoare!