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