In diesem Artikel erfahren Sie mehr über PHP-Ausnahmen von Grund auf. Diese Konzepte werden in vielen großen, skalierbaren und objektorientierten Anwendungen und Frameworks verwendet. Nutzen Sie diese Sprachfunktion, um Ihre Fähigkeiten als Entwickler von Webanwendungen zu verbessern.
Bevor wir mit allen Erklärungen beginnen, möchte ich zuerst ein Beispiel zeigen.
Angenommen, Sie möchten die Fläche eines Kreises anhand des angegebenen Radius berechnen. Diese Funktion wird das tun:
function circle_area ($ radius) return pi () * $ radius * $ radius;
Es ist sehr einfach, prüft jedoch nicht, ob der Radius eine gültige Zahl ist. Jetzt machen wir das und werfen eine Ausnahme, wenn der Radius eine negative Zahl ist:
function circle_area ($ radius) // radius darf nicht negativ sein wenn ($ radius < 0) throw new Exception('Invalid Radius: ' . $radius); else return pi() * $radius * $radius;
Mal sehen, was passiert, wenn wir es mit einer negativen Nummer anrufen:
$ radius = -2; echo "Circle Radius: $ radius => Circle Area:". Kreisbereich ($ radius). "\ n"; Echo "andere Linie";
Das Skript stürzt mit der folgenden Meldung ab:
Fataler Fehler: Nicht erfasste Ausnahme 'Exception' mit der Nachricht 'Invalid Radius: -2' in C: \ wamp \ www \ test \ test.php: 19 Stack-Trace: # 0 C: \ wamp \ www \ test \ test.php (7) : circle_area (-2) # 1 main geworfen C: \ wamp \ www \ test \ test.php Online 19
Da es sich um einen schwerwiegenden Fehler handelte, erfolgte danach keine weitere Code-Ausführung. Möglicherweise möchten Sie jedoch nicht, dass Ihre Skripts immer dann angehalten werden, wenn eine Ausnahme auftritt. Glücklicherweise können Sie sie "fangen" und damit umgehen.
Diesmal machen wir ein Array von Radiuswerten:
$ radius_array = array (2, -2,5, -3); foreach ($ radius_array als $ radius) try echo "Kreisradius: $ radius => Circle Area:"). Kreisbereich ($ radius). "\ n"; catch (Ausnahme $ e) echo 'Caught Exception:', $ e-> getMessage (), "\ n";
Jetzt erhalten wir diese Ausgabe:
Kreisradius: 2 => Kreisfläche: 12.566370614359 Gefangene Ausnahme: Ungültiger Radius: -2 Kreisradius: 5 => Kreisfläche: 78.539816339745 Gefangene Ausnahme: Ungültiger Radius: -3
Es sind keine Fehler mehr vorhanden und das Skript wird weiter ausgeführt. So fangen Sie Ausnahmen auf.
Ausnahmen gibt es schon länger in anderen objektorientierten Programmiersprachen. Es wurde zuerst in PHP mit Version 5 übernommen.
Per Definition wird eine Ausnahme "ausgelöst", wenn ein außergewöhnliches Ereignis eintritt. Dies kann so einfach sein wie eine 'Division durch Null' oder jede andere Art von ungültiger Situation.
Neue Ausnahme auslösen ('Einige Fehlermeldung.');
Dies kann ähnlich wie andere grundlegende Fehler klingen, die Sie schon oft gesehen haben. Ausnahmen haben jedoch einen anderen Mechanismus.
Ausnahmen sind eigentlich Objekte und Sie haben die Möglichkeit, sie zu "fangen" und bestimmten Code auszuführen. Dies geschieht mit Hilfe von Try-Catch-Blöcken:
try // etwas Code geht hier //, was eine Ausnahme auslösen kann catch (Ausnahme $ e) // Der Code wird hier nur ausgeführt // wenn eine Ausnahme im try-Block oben aufgetreten ist
Wir können jeden Code in einen Try-Block einschließen. Der folgende 'catch'-Block wird zum Abfangen einer Ausnahme verwendet, die möglicherweise innerhalb des try-Blocks ausgelöst wurde. Der catch-Block wird nie ausgeführt, wenn es keine Ausnahmen gab. Sobald eine Ausnahme auftritt, springt das Skript sofort zum catch-Block, ohne weiteren Code auszuführen.
In diesem Artikel finden Sie weitere Beispiele, die die Leistungsfähigkeit und Flexibilität der Verwendung von Ausnahmen anstelle von einfachen Fehlermeldungen zeigen sollen.
Wenn eine Ausnahme von einer Funktion oder einer Klassenmethode ausgelöst wird, geht sie an denjenigen, der diese Funktion oder Methode aufgerufen hat. Und es tut dies so lange, bis es die Spitze des Stapels erreicht oder gefangen wird. Wenn es die Spitze des Stapels erreicht und nie aufgerufen wird, wird ein schwerwiegender Fehler angezeigt.
Zum Beispiel haben wir hier eine Funktion, die eine Ausnahme auslöst. Wir nennen diese Funktion aus einer zweiten Funktion. Zum Schluss rufen wir die zweite Funktion aus dem Hauptcode auf, um diesen sprudelnden Effekt zu demonstrieren:
Funktionsleiste () Neue Exception werfen ('Nachricht von Bar ().'); function foo () bar (); try foo (); catch (Ausnahme $ e) echo 'Ausnahme:', $ e-> getMessage (), "\ n";
Wenn wir also foo () aufrufen, versuchen wir, mögliche Ausnahmen zu erkennen. Obwohl foo () keinen wirft, aber bar (), sprudelt es immer noch und wird am oberen Ende erwischt, so dass wir eine Ausgabe erhalten, die besagt: "Ausnahme: Nachricht von Bar ()."
Da Ausnahmen sprudeln, können sie von überall her kommen. Zur Vereinfachung unserer Arbeit verfügt die Exception-Klasse über Methoden, mit denen wir die Quelle jeder Ausnahme ermitteln können.
Sehen wir uns ein Beispiel an, das mehrere Dateien und mehrere Klassen umfasst.
Zuerst haben wir eine User-Klasse und speichern sie als user.php:
Klasse Benutzer public $ name; öffentliche $ email; öffentliche Funktion save () $ v = new Validator (); $ v-> validate_email ($ this-> email); //… speichern echo "Benutzer gespeichert."; wahr zurückgeben;
Es verwendet eine andere Klasse namens Validator, die wir in validator.php ablegen:
class Validator öffentliche Funktion validate_email ($ email) if (! filter_var ($ email, FILTER_VALIDATE_EMAIL)) neue Exception werfen ('Email ist ungültig');
Von unserem Hauptcode aus erstellen wir ein neues Benutzerobjekt, legen den Namen und die E-Mail-Werte fest. Wenn wir die save () -Methode aufrufen, wird die Validator-Klasse zur Überprüfung des E-Mail-Formats verwendet. Dies kann zu einer Ausnahme führen:
include ('user.php'); include ('validator.php'); $ u = neuer Benutzer (); $ u-> name = 'foo'; $ u-> email = '$!% # $% # *'; $ u-> save ();
Wir möchten jedoch die Ausnahme abfangen, sodass keine schwerwiegende Fehlermeldung angezeigt wird. Und dieses Mal werden wir uns ausführlich mit dieser Ausnahme befassen:
include ('user.php'); include ('validator.php'); try $ u = neuer Benutzer (); $ u-> name = 'foo'; $ u-> email = '$!% # $% # *'; $ u-> save (); catch (Ausnahme $ e) echo "Message:". $ e-> getMessage (). "\ n \ n"; echo "Datei:". $ e-> getFile (). "\ n \ n"; Echo "Line:". $ e-> getLine (). "\ n \ n"; Echo "Trace: \ n". $ e-> getTraceAsString (). "\ n \ n";
Der obige Code erzeugt diese Ausgabe:
Nachricht: E-Mail ist ungültig Datei: C: \ wamp \ www \ test \ validator.php Zeile: 7 Trace: # 0 C: \ wamp \ www \ test \ user.php (11): Validator-> validate_email ('$! % # $% # * ') # 1 C: \ wamp \ www \ test \ test.php (12): Benutzer-> Speichern () # 2 main
Ohne auf eine einzige Codezeile zu schauen, können wir also feststellen, woher die Ausnahme kam. Wir können den Dateinamen, die Zeilennummer, die Ausnahmemeldung und mehr sehen. Die Trace-Daten zeigen sogar die genauen Codezeilen, die ausgeführt wurden.
Die Struktur der Standard-Exception-Klasse ist im PHP-Handbuch dargestellt, in dem Sie alle Methoden und Daten sehen können, die im Lieferumfang enthalten sind:
Da dies ein objektorientiertes Konzept ist und Exception eine Klasse ist, können wir es tatsächlich erweitern, um unsere eigenen benutzerdefinierten Exceptions zu erstellen.
Beispielsweise möchten Sie möglicherweise nicht alle Details einer Ausnahme für den Benutzer anzeigen. Stattdessen können Sie eine benutzerfreundliche Nachricht anzeigen und die Fehlermeldung intern protokollieren:
// für Datenbankprobleme verwendet werden Klasse DatabaseException erweitert Exception // Sie können beliebige benutzerdefinierte Methoden hinzufügen. public function log () // diesen Fehler irgendwo protokollieren //… // für Dateisystemprobleme Klasse FileException erweitert Ausnahme //…
Wir haben gerade zwei neue Arten von Ausnahmen erstellt. Und sie können benutzerdefinierte Methoden haben.
Wenn wir die Ausnahme abfangen, können wir eine feste Nachricht anzeigen und die benutzerdefinierten Methoden intern aufrufen:
function foo () //… // Mit der Datenbank ist ein Fehler aufgetreten. throw new DatabaseException (); try // füge den gesamten Code hier ein //… foo (); catch (FileException $ e) die ("Wir haben anscheinend Probleme mit dem Dateisystem. Wir entschuldigen uns für die Unannehmlichkeiten."); catch (DatabaseException $ e) // Aufruf unserer neuen Methode $ e-> log (); // mit einem Meldungswürfel beenden ("Wir haben anscheinend Datenbankprobleme. Wir entschuldigen uns für die Unannehmlichkeiten."); catch (Ausnahme $ e) echo 'Ausnahme bei Auslösung:'. $ e-> getMessage (). "\ n";
Dies ist das erste Mal, dass wir ein Beispiel mit mehreren catch-Blöcken für einen einzelnen try-Block betrachten. Auf diese Weise können Sie verschiedene Arten von Ausnahmen abfangen, um sie anders zu behandeln.
In diesem Fall werden wir eine DatabaseException abfangen und nur dieser catch-Block wird ausgeführt. In diesem Blog können wir unsere neuen benutzerdefinierten Methoden aufrufen und dem Benutzer eine einfache Nachricht anzeigen.
Bitte beachten Sie, dass der catch-Block mit der Standard-Exception-Klasse als letztes kommen muss, da unsere neuen untergeordneten Klassen auch noch als diese Klasse betrachtet werden. Zum Beispiel wird 'DatabaseException' auch als 'Ausnahme' betrachtet, so dass es dort erwischt werden kann, wenn die Reihenfolge umgekehrt ist.
Möglicherweise möchten Sie nicht immer nach Ausnahmen in Ihrem gesamten Code suchen, indem Sie alles in try-catch-Blöcke einschließen. Nicht erfasste Ausnahmen zeigen dem Benutzer jedoch eine detaillierte Fehlermeldung an, die in einer Produktionsumgebung ebenfalls nicht ideal ist.
Es gibt tatsächlich eine Möglichkeit, die Handhabung aller nicht erfassten Ausnahmen zu zentralisieren, sodass Sie die Ausgabe von einem einzigen Ort aus steuern können.
Dazu verwenden wir die Funktion set_exception_handler ():
set_exception_handler ('exception_handler'); function exception_handler ($ e) // public message echo "Etwas ist schief gelaufen. \ n"; // halb verstecktes Echo "
Wie Sie sehen, wurde das Skript nach der ersten Ausnahme abgebrochen und die zweite nicht ausgeführt. Dies ist das erwartete Verhalten von nicht erfassten Ausnahmen.
Wenn Sie möchten, dass Ihr Skript nach einer Ausnahme weiterhin ausgeführt wird, müssen Sie stattdessen einen try-catch-Block verwenden.
Wir beenden dieses Tutorial mit der Erstellung einer benutzerdefinierten MySQL-Exception-Klasse, die einige nützliche Funktionen enthält, und sehen, wie wir sie verwenden können.
Klasse MysqlException erweitert Exception // Pfad zur Protokolldatei private $ log_file = 'mysql_errors.txt'; öffentliche Funktion __construct () $ code = mysql_errno (); $ message = mysql_error (); // Öffnen Sie die Protokolldatei, um if ($ fp = fopen ($ this-> log_file, 'a')) anzufügen. "Code: $ code -". "Nachricht: $ message \ n"; fwrite ($ fp, $ log_msg); fclose ($ fp); // übergeordneter Konstruktor aufrufen parent :: __ construct ($ message, $ code);
Sie stellen möglicherweise fest, dass wir den Code fast vollständig in den Konstruktor einfügen. Wenn eine Ausnahme ausgelöst wird, ist dies wie das Erstellen eines neuen Objekts. Aus diesem Grund wird der Konstruktor immer zuerst aufgerufen. Am Ende des Konstruktors stellen wir außerdem sicher, dass der übergeordnete Konstruktor aufgerufen wird.
Diese Ausnahme wird ausgelöst, wenn ein MySQL-Fehler auftritt. Anschließend werden die Fehlernummer und die Nachricht direkt von mysql abgerufen und diese Informationen zusammen mit dem Zeitstempel in einer Protokolldatei gespeichert. In unserem Code können wir diese Ausnahme abfangen, dem Benutzer eine einfache Nachricht anzeigen und die Ausnahmeklasse die Protokollierung für uns übernehmen lassen.
Versuchen wir beispielsweise, eine Verbindung zu MySQL herzustellen, ohne Benutzer- oder Kennwortinformationen anzugeben:
Versuchen Sie // versuchen Sie eine Verbindung herzustellen, wenn (! @mysql_connect ()) neue MysqlException werfen; catch (MysqlException $ e) die ("Wir haben anscheinend Datenbankprobleme. Wir entschuldigen uns für die Unannehmlichkeiten.");
Der Fehlerunterdrückungsoperator (@) muss vor dem Aufruf von mysql_connect () vorangestellt werden, damit er dem Benutzer den Fehler nicht anzeigt. Wenn die Funktion fehlschlägt, wird eine Ausnahme ausgelöst und dann abgefangen. Nur unsere benutzerfreundliche Nachricht wird dem Browser angezeigt.
Die MysqlException-Klasse kümmert sich automatisch um die Fehlerprotokollierung. Wenn Sie die Protokolldatei öffnen, finden Sie diese Zeile:
[2010-05-05 21:41:23] Code: 1045 - Nachricht: Zugriff für Benutzer 'SYSTEM' @ 'localhost' verweigert (mit Kennwort: NEIN)
Fügen Sie unserem Beispiel mehr Code hinzu und geben Sie auch korrekte Anmeldeinformationen an:
try // Verbindung sollte einwandfrei funktionieren, wenn (! @mysql_connect ('localhost', 'root', ")) neue MysqlException auslösen; // eine Datenbank auswählen (die möglicherweise nicht vorhanden ist) if (! mysql_select_db ('my_db' )) throw new MysqlException; // Versuch einer Abfrage (die einen Syntaxfehler enthalten kann) if (! $ result = mysql_query ("INSERT INTO foo SET bar = '42")) Neue MysqlException auslösen; catch ( MysqlException $ e) die ("Wir haben anscheinend Datenbankprobleme. Wir entschuldigen uns für die Unannehmlichkeiten.");
Wenn die Datenbankverbindung erfolgreich ist, die Datenbank 'my_db' jedoch fehlt, finden Sie dies in den Protokollen:
[2010-05-05 21:55:44] Code: 1049 - Nachricht: Unbekannte Datenbank 'my_db'
Wenn die Datenbank vorhanden ist, die Abfrage jedoch aufgrund eines Syntaxfehlers fehlschlägt, wird dies möglicherweise im Protokoll angezeigt:
[2010-05-05 21:58:26] Code: 1064 - Nachricht: Sie haben einen Fehler in Ihrer SQL-Syntax. Überprüfen Sie das Handbuch, das Ihrer MySQL-Server-Version entspricht, auf die richtige Syntax, die in der Nähe von "42" in Zeile 1 verwendet werden soll
Wir können das obige Codebeispiel noch sauberer machen, indem wir unsere eigene Datenbankklasse schreiben, die das Auslösen der Ausnahmen übernimmt. Dieses Mal werde ich einige "magische" Funktionen von PHP verwenden, um diese Klasse zu erstellen.
Am Ende möchten wir, dass unser Hauptcode so aussieht:
try Database :: connect ('localhost', 'root', "); Database :: select_db ('test'); $ result = Database :: query (" INSERT INTO foo SET bar = '42 "); catch (MysqlException $ e) die ("Wir haben anscheinend Datenbankprobleme. Wir entschuldigen uns für die Unannehmlichkeiten.");
Es ist schön und sauber. Wir prüfen nicht bei jedem einzelnen Datenbankaufruf auf Fehler. Diese neue Datenbankklasse ist dafür verantwortlich, Ausnahmen auszulösen, wenn Fehler auftreten. Und da diese Ausnahmen sprudeln, werden sie am Ende von unserem Sperrblock erwischt.
Und hier ist die magische Datenbankklasse:
class Database // Jeder statische Funktionsaufruf ruft diese öffentliche statische Funktion __callStatic ($ name, $ args) // Funktion auf, die als $ function = 'mysql_' bezeichnet werden soll. $ name; // Gibt es die Funktion? if (! function_exists ($ function)) // Eine reguläre Ausnahme auslösen. Neue Exception ausgeben ("Ungültige Mysql-Funktion: $ function."); // Aufruf der MySQL-Funktion $ ret = @call_user_func_array ($ function, $ args); // Sie geben bei Fehlern FALSE zurück, wenn ($ ret === FALSE) // Db-Exception auslösen. Neue MysqlException auslösen. // Rückgabe des zurückgegebenen Wertes return $ ret;
Es hat nur eine Methode und wird aufgerufen, wenn wir für diese Klasse eine statische Methode aufrufen. Sie können mehr über dieses Konzept hier lesen: PHP-Überladung.
Beim Aufruf von Database :: connect () ruft dieser Code automatisch mysql_connect () auf, übergibt die Argumente, sucht nach Fehlern, wirft bei Bedarf Ausnahmen aus und gibt den zurückgegebenen Wert aus dem Funktionsaufruf zurück. Es wirkt im Grunde wie ein mittlerer Mann und erledigt die schmutzige Arbeit.
Ich hoffe, Sie haben dieses Tutorial genossen und daraus gelernt. Nun sollten Sie dieses Thema besser verstehen. Testen Sie, ob Sie PHP-Ausnahmen in Ihrem nächsten Projekt verwenden können. Bis zum nächsten Mal!