Sie sollten die Ausnahme nicht abfangen, es sei denn, Sie beabsichtigen, etwas Sinnvolles zu tun .
"Etwas Sinnvolles" könnte eine davon sein:
Behandlung der Ausnahme
Die naheliegendste sinnvolle Aktion besteht darin, die Ausnahme zu behandeln, z. B. indem eine Fehlermeldung angezeigt und der Vorgang abgebrochen wird:
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
echo "Error while connecting to database!";
die;
}
Protokollierung oder teilweise Bereinigung
Manchmal wissen Sie nicht, wie Sie eine Ausnahme in einem bestimmten Kontext richtig behandeln sollen. Vielleicht fehlen Ihnen Informationen über das "große Ganze", aber Sie möchten den Fehler so nah wie möglich an dem Punkt protokollieren, an dem er aufgetreten ist. In diesem Fall möchten Sie möglicherweise Folgendes fangen, protokollieren und erneut werfen:
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
logException($e); // does something
throw $e;
}
In einem verwandten Szenario sind Sie am richtigen Ort, um eine Bereinigung für den fehlgeschlagenen Vorgang durchzuführen, aber nicht um zu entscheiden, wie der Fehler auf der obersten Ebene behandelt werden soll. In früheren PHP-Versionen wurde dies als implementiert
$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
$connect->insertSomeRecord();
}
catch (Exception $e) {
$connect->disconnect(); // we don't want to keep the connection open anymore
throw $e; // but we also don't know how to respond to the failure
}
PHP 5.5 hat das finally
Schlüsselwort eingeführt. Für Bereinigungsszenarien gibt es jetzt eine andere Möglichkeit, dies zu erreichen. Wenn der Bereinigungscode ausgeführt werden muss, unabhängig davon, was passiert ist (dh sowohl bei Fehlern als auch bei Erfolg), ist dies jetzt möglich, während die Auslösung von ausgelösten Ausnahmen transparent ist:
$connect = new CONNECT($db, $user, $password, $driver, $host);
try {
$connect->insertSomeRecord();
}
finally {
$connect->disconnect(); // no matter what
}
Fehlerabstraktion (mit Ausnahme der Verkettung)
Ein dritter Fall ist, wenn Sie viele mögliche Fehler logisch unter einem größeren Dach zusammenfassen möchten. Ein Beispiel für eine logische Gruppierung:
class ComponentInitException extends Exception {
// public constructors etc as in Exception
}
class Component {
public function __construct() {
try {
$connect = new CONNECT($db, $user, $password, $driver, $host);
}
catch (Exception $e) {
throw new ComponentInitException($e->getMessage(), $e->getCode(), $e);
}
}
}
In diesem Fall möchten Sie nicht, dass die Benutzer von Component
wissen, dass es über eine Datenbankverbindung implementiert wird (möglicherweise möchten Sie Ihre Optionen offen halten und in Zukunft dateibasierten Speicher verwenden). Ihre Spezifikation für Component
würde also sagen, dass "im Falle eines Initialisierungsfehlers ComponentInitException
ausgelöst wird". Dies ermöglicht es Verbrauchern Component
, Ausnahmen des erwarteten Typs abzufangen und gleichzeitig dem Debugging-Code den Zugriff auf alle (implementierungsabhängigen) Details zu ermöglichen .
Bereitstellung eines umfassenderen Kontexts (mit Ausnahme der Verkettung)
Schließlich gibt es Fälle, in denen Sie möglicherweise mehr Kontext für die Ausnahme bereitstellen möchten. In diesem Fall ist es sinnvoll, die Ausnahme in eine andere zu packen, die weitere Informationen darüber enthält, was Sie versucht haben, als der Fehler aufgetreten ist. Beispielsweise:
class FileOperation {
public static function copyFiles() {
try {
$copier = new FileCopier(); // the constructor may throw
// this may throw if the files do no not exist
$copier->ensureSourceFilesExist();
// this may throw if the directory cannot be created
$copier->createTargetDirectory();
// this may throw if copying a file fails
$copier->performCopy();
}
catch (Exception $e) {
throw new Exception("Could not perform copy operation.", 0, $e);
}
}
}
Dieser Fall ähnelt dem obigen (und das Beispiel ist wahrscheinlich nicht das beste, das man sich vorstellen kann), zeigt jedoch, warum mehr Kontext bereitgestellt werden muss: Wenn eine Ausnahme ausgelöst wird, wird angezeigt, dass die Dateikopie fehlgeschlagen ist. Aber warum ist es gescheitert? Diese Informationen werden in den umschlossenen Ausnahmen bereitgestellt (von denen es mehr als eine Ebene geben könnte, wenn das Beispiel viel komplizierter wäre).
Der Wert dieser Vorgehensweise wird veranschaulicht, wenn Sie an ein Szenario denken, in dem beispielsweise beim Erstellen eines UserProfile
Objekts Dateien kopiert werden, weil das Benutzerprofil in Dateien gespeichert ist und die Transaktionssemantik unterstützt: Sie können Änderungen "rückgängig machen", da sie nur für a ausgeführt werden Kopie des Profils, bis Sie festschreiben.
In diesem Fall, wenn Sie es getan haben
try {
$profile = UserProfile::getInstance();
}
Wenn als Ergebnis ein Ausnahmefehler "Zielverzeichnis konnte nicht erstellt werden" abgefangen wird, besteht ein Recht auf Verwirrung. Das Umschließen dieser "Kern" -Ausnahme in Schichten anderer Ausnahmen, die Kontext bereitstellen, erleichtert die Behandlung des Fehlers erheblich ("Erstellen der Profilkopie fehlgeschlagen" -> "Dateikopiervorgang fehlgeschlagen" -> "Zielverzeichnis konnte nicht erstellt werden").
finally
Konstrukt nicht unterstützt (zumindest noch nicht) ... Das ist also raus, was bedeutet, dass wir auf schmutzige Dinge wie diese zurückgreifen müssen ...finally
in PHP kein .error_code
Eigenschaft, die überprüft werden kann, um den zugrunde liegenden Fehler abzurufen Code. Wenn Sie nur in der Lage sind, einige dieser Fehler sinnvoll zu behandeln, möchten Sie sie wahrscheinlich abfangen, überprüfen und wenn Sie den Fehler nicht behandeln können - erneut werfen.Nun, es geht darum, die Abstraktion aufrechtzuerhalten. Daher würde ich vorschlagen, die Ausnahmeverkettung zu verwenden, um direkt zu werfen. Lassen Sie mich das Konzept der undichten Abstraktionen erklären
Angenommen, Sie bauen ein Modell. Das Modell soll die gesamte Datenpersistenz und -validierung vom Rest der Anwendung abstrahieren. Was passiert nun, wenn Sie einen Datenbankfehler erhalten? Wenn Sie das erneut werfen
DatabaseQueryException
, verlieren Sie die Abstraktion. Um zu verstehen, warum, denken Sie eine Sekunde über die Abstraktion nach. Es ist Ihnen egal, wie das Modell die Daten speichert, nur dass dies der Fall ist. Ebenso ist es Ihnen egal, was in den zugrunde liegenden Systemen des Modells schief gelaufen ist, nur dass Sie wissen, dass etwas schief gelaufen ist und ungefähr, was schief gelaufen ist.Wenn Sie also die DatabaseQueryException erneut auslösen, verlieren Sie die Abstraktion und benötigen den aufrufenden Code, um die Semantik der Vorgänge unter dem Modell zu verstehen. Erstellen Sie stattdessen ein Generikum
ModelStorageException
und wickeln Sie das gefangeneDatabaseQueryException
darin ein. Auf diese Weise kann Ihr aufrufender Code weiterhin versuchen, den Fehler semantisch zu behandeln, aber es spielt keine Rolle, welche Technologie dem Modell zugrunde liegt, da Sie nur Fehler aus dieser Abstraktionsschicht offenlegen. Noch besser ist, dass Sie, da Sie die Ausnahme umbrochen haben, wenn sie bis zum Anschlag sprudelt und protokolliert werden muss, die ausgelöste Root-Ausnahme verfolgen können (entlang der Kette gehen), sodass Sie immer noch alle Debugging-Informationen haben, die Sie benötigen!Fangen Sie nicht einfach dieselbe Ausnahme ab und werfen Sie sie erneut, es sei denn, Sie müssen eine Nachbearbeitung durchführen. Aber ein Block wie
} catch (Exception $e) { throw $e; }
ist sinnlos. Sie können die Ausnahmen jedoch erneut einschließen, um einen signifikanten Abstraktionsgewinn zu erzielen.quelle
IMHO, eine Ausnahme zu fangen, um sie einfach wieder zu werfen, ist nutzlos . In diesem Fall fangen Sie es einfach nicht ab und lassen Sie früher aufgerufene Methoden damit umgehen (auch bekannt als Methoden, die im Aufrufstapel 'oben' sind) .
Wenn Sie es erneut werfen, ist es auf jeden Fall eine gute Vorgehensweise, die abgefangene Ausnahme mit der neuen zu verketten, die Sie auslösen, da die Informationen, die die abgefangene Ausnahme enthält, beibehalten werden. Ein erneutes Werfen ist jedoch nur dann sinnvoll, wenn Sie der abgefangenen Ausnahme Informationen hinzufügen oder etwas behandeln. Dies kann ein Kontext, Werte, Protokollierung, Freigabe von Ressourcen usw. sein.
Ein Weg , um einige Informationen hinzuzufügen ist , die zu verlängern
Exception
Klasse, haben Ausnahmen wieNullParameterException
,DatabaseException
usw. Mehr über dieses ermöglichen die developper nur einige Ausnahmen zu fangen , dass er verarbeiten kann. Zum Beispiel kann man nur fangenDatabaseException
und versuchen zu lösen, was das verursacht hatException
, wie das Wiederverbinden mit der Datenbank.quelle
Sie müssen sich die Best Practices für Ausnahmen in PHP 5.3 ansehen
Die Ausnahmebehandlung in PHP ist keineswegs neu. Unter dem folgenden Link sehen Sie zwei neue Funktionen in PHP 5.3, die auf Ausnahmen basieren. Die erste ist verschachtelte Ausnahmen und die zweite ist eine neue Reihe von Ausnahmetypen, die von der SPL-Erweiterung angeboten werden (die jetzt eine Kernerweiterung der PHP-Laufzeit ist). Beide neuen Funktionen haben ihren Weg in das Buch der Best Practices gefunden und verdienen eine eingehende Prüfung.
http://ralphschindler.com/2010/09/15/exception-best-practices-in-php-5-3
quelle
Normalerweise denken Sie so.
Eine Klasse kann viele Arten von Ausnahmen auslösen, die nicht übereinstimmen. Sie erstellen also eine Ausnahmeklasse für diese Klasse oder diesen Klassentyp und werfen diese aus.
Der Code, der die Klasse verwendet, muss also nur einen Ausnahmetyp abfangen.
quelle