// der php hacker

// archiv

Versuchen und fangen: Ein paar Hinweise zu try-catch

Geschrieben am 26. Apr 2009 von Cem Derin

Ich wollte schon länger ein paar Worte zu diesem Thema schreiben. Ausschlaggebend war die Tatsache, dass viele Entwickler (oder die, die sich dafür halten), Exceptions durchaus einsetzen, aber offensichtlich nie verstanden haben, wie das Prinzip funktioniert, denn die Ausnahmebehandlung wirkt wie aus einem Beispielquelltext einer beliebigen Dokumentation. Wie man Exceptions effektiv einsetzen kann, möchte ich im folgenden erklären.

Schaut man in das PHP-Handbuch zu dem Thema “Exceptions” nach, wird man ungefähr so einen Code vorfinden:

<?php
	try {
		throw new Exception('error');
	} catch(Exception $e) {
		echo $e->getMessage();
	}
?>

Charakteristisch ist zum einen die Tatsache, dass die Exception in der Variable $e gefangen wird. Schaut man sich Produktivquelltext an, wird das auch dort meist der Fall sein. Das jedoch ist nicht weiter schlimm, immerhin wird für Iterationen auch gerne $i als Zähler verwendet. Darüberhinaus jedoch haben diese Beispiele eine weitere Eigenart: Es wird in der Regel nur eine Exception gefangen – und diese meist auch nur von der Exception-Mutterklasse.

Schaut man sich die Signatur des Fang-Blockes genauer an, wird einem Auffallen, dass man angibt, welche Klassen-Instanz man fangen will. Aber warum sollte man eigene Exceptions werfen? Ein kleiner Test lässt uns feststellen, dass Exceptions immer von der SPL-Standardklasse Exception abgeleitet werden müssen.

<?php
	class Test {
		public function __construct($msg) {
			$this->msg = $msg;
		}

		public function getMessage() {
			return $this->msg;
		}
	}

	try {
		throw new Test('error');
	} catch(Exception $e) {
		echo $e->getMessage();
	}
?>

Wir können also eigene Exceptions werfen. Tragen wir diese in die catch-Signatur ein und wird eine Instanz der SPL-Exception geworfen, wird diese nicht gefangen. So weit, so gut: Aber was soll das bringen?

Hier kommen wir zu dem Punkt, den viele außer acht lassen: Man kann das fangen von Exceptions stapeln. Dazu hier ein Beispielcode:

<?php
	class FirstException extends Exception {}
	class SecondException extends FirstException {}
	class ThirdException extends SecondException {}

	function throwit() {
		throw new SecondException('catch me if you can!');
	}

	try {
		throwit();
	} catch(ThirdException $e) {
		echo 'Third branch';
	} catch(SecondException $e) {
		echo 'Second branch';
	} catch(FirstException $e) {
		echo 'First Branch';
	} catch(Exception $e) {
		echo 'Plain';
	}
?>

Mann kann die catch-Blöcke Stapeln. D.h., dass man mehrere Instanzen deklarieren kann, die man fangen möchte. Die erste Signatur, auf die die geworfene Instanz zutrifft, wird ausgeführt. Es empfiehlt sich dieser Stelle immer einen allerletzten Block zu definieren, in dem eine Exception-Instanz gefangen wird – so stellt man sicher, dass das Script eine kontrollierte Fehlerbehandlung durchführen kann.

Das steht zwar auch alles in der offiziellen Dokumentation, aber offensichtlich lesen die Leute immer nur die Quelltextbeispiele … und im Beispielquelltext zu try-catch wird nur ein catch-Block definiert  :-)


#001
26. Apr 2009

Hallo,

Ich verwende Excpetions wirklich gerne, noch dazu wo doch eigene exceptions das leben um längen einfacher machen.

zb.

class DBException extends Exception {}
class LayoutException extends Exception {}

try {
// get results from DB
// manipulate them
// display them
}catch(DBException $e){
// Fehler mit der Datenbank, reagiere entsprechend darauf
}catch(LayoutException $e){
// Fehler beim Layout erstellen, reagiere darauf
}catch(Exception $e){
// Safty Exception, reagiere entsprechend darauf.
}

// kommentieren

// senden
theme von mir, software von wordpress, grid von 960 grid system. funktioniert in allen browsern, aber der safari bekommt das mit der schrift am schönsten hin.