php.de

Zurück   php.de > php.de Intern > Wiki Diskussionsforum > Tutorials

Tutorials Hier findest Du Tutorials, welche nach und nach ein fertiges Script ergeben. Sehen, lernen & verstehen!

Antwort
 
LinkBack (5) Themen-Optionen Thema bewerten
Alt 21.11.2007, 17:28  
Erfahrener Benutzer
 
Registriert seit: 21.05.2008
Beiträge: 9.937
Zergling-new wird schon bald berühmt werden
Standard PHP: Exceptions - Teil 1

Vorweg: Tut mir Leid für diesen Text-Overhead, er war plötzlich da!


Was sind Exceptions?

Exception bedeutet übersetzt Ausnahme und stellt in der objekt-orientierten Programmierung eine elegante Möglichkeit dar, bei besonderen oder schweren Fehlern den aktuellen Programmkontext zu verlassen (!) um ihn mit einer Fehlerbehandlung fortzuführen.

Ähnlich wie return für das Abliefern eines Ergebnisses funktioniert, funktioniert das Werfen (throw) von Exceptions, also einem Fehler-Objekt, nur wird das Programm nun nicht zwingend in der übergeordneten, aufrufenden Umgebung landen, sondern dort, wo es erwartet und aufgefangen (catch) wird.




Wie wirft und fängt man Exceptions?

Exception-Handling unterteilt sich in zwei Blöcke, logisch wie syntaktisch.
In try wird ein Algorithmus ausgeführt, der, schlägt er fehl, eine Exception werfen könnte.

PHP-Code:
<?php
// ein kleiner dateibasierter Counter
try {
  
$counter file_get_contents("counter.txt");
  if (!
is_numeric($counter)) { // kein gültiger Counter-Wert in der Datei?
    
throw new Exception("invalid counter value"); // dann Exception werfen
  
}
  
file_put_contents("counter.txt"$counter 1);
}
?>
Diese Exception können wir auffangen, wenn der Versuch (try) fehlgeschlagen ist:
PHP-Code:
<?php
try {
  
$counter file_get_contents("counter.txt");
  if (!
is_numeric($counter)) {
    throw new 
Exception("invalid counter value");
  }
  
file_put_contents("counter.txt"$counter 1);
  echo 
$counter 1;
} catch (
Exception $e) {
  echo 
$e->getMessage(); // die Klasse Exception stellt diese Methode zur Verfügung
}
?>
Von throw new Exception("invalid counter value"); aus springen wir direkt in den catch-Block und lassen uns die Fehlermeldung ausgeben!

Dabei spielt es keine Rolle, ob die Exception im try-Block direkt geworfen wurde oder nur von einer Funktion, die darin verwendet wurde.

Denkbar wäre also auch folgendes Konstrukt:
PHP-Code:
<?php
function getCounterValue()
{
  
$counter file_get_contents("counter.txt");
  if (!
is_numeric($counter)) {
    throw new 
Exception("invalid counter value");
  }
  return 
$counter;
}
function 
setCounterValue($value)
{
  
file_put_contents("counter.txt"$value);  
}

try {
  
$counter getCounterValue() + 1;
  
setCounterValue($counter);
  echo 
"Hello visitor number "$counter;
} catch (
Exception $e) {
  echo 
$e->getMessage(); // "invalid counter value"
}
?>
Das Werfen der Exception wird also sogar ausserhalb des try-Blockes deklariert. Relevant ist jedoch, ob dieser Code im try-Block ausgeführt wird und das ist hier der Fall.




Wann bzw. wo wirft man Exceptions?

Exceptions sind Ausnahmen und ich teile die Meinung aus "Der Pragmatische Programmierer", dass Exceptions die Ausnahme sein sollten.

Das gewählte Beispiel ist absichtlich ein schlechtes! Warum?

Es ist davon auszugehen, dass bei der ersten Verwendung des Skriptes die counter.txt nicht existiert und somit is_numeric($counter) fehlschlägt. Es ist also keine Ausnahme, sondern ein Zustand, der garantiert eintreten wird (wenn auch nur hoffentlich nur einmalig bei der Initiierung).

Richtigerweise sollte man die Datei auf Nicht-Existenz prüfen und dann mit einer 0 initiiert anlegen. Erst wenn dann der Lese- oder sogar Schreibvorgang fehlschlägt, kann man von einer echten Ausnahme reden und eine Exception werfen.

Eine Faustregel:
Exceptions nur verwenden, wenn man behaupten könnte, dass dieser Fehler nie passieren sollte!

Eine ziemlich schwammige Aussage eigentlich, denn letztlich sollte eine Exception ja nie ausgelöst werden, die Übergänge sind sowieso fließend. Trotzdem gibt es einen Unterschied zwischen "sollte nie" und "kommt schonmal vor".


Für unser Beispiel hieße das also:
PHP-Code:
<?php
try {
  if (!
file_exists("counter.txt")) {
    
$counter 0;
  } else {
    
$counter file_get_contents("counter.txt");
  }
  if (!
is_numeric($counter)) {
    throw new 
Exception("invalid counter value");
  }
  
$counter++;
  
file_put_contents("counter.txt"$counter);
  echo 
"Hello visitor number "$counter;
} catch (
Exception $e) {
  echo 
$e->getMessage();
}
?>
Auch dieses Beispiel ist natürlich ungeschickt gewählt, da sich die Fehlerbehandlung zufällig sogar direkt unter dem auslösenden Fehler befindet. Üblicherweise ist das nicht der Fall. Dazu kommen wir im kommenden Kapitel:




Wann bzw. wo fängt man Exceptions?

Exceptions fängt man dort, wo man das Problem am besten lösen kann. Das heißt in dem Block, an dem man mit ausreichender Sicherheit sagen kann, die Ausnahme und ihre Tragweite verstanden zu haben.

Gehen wir von einer einfachen Variante aus:
Eine zentrale index.php (eine sogenannte Bootstrap-Datei) bekommt die Parameter module=gallery&show=silvester0607 übergeben. Das Modul "gallery" soll also die Bilder von "silvester0607" laden und anzeigen.
Nun wird versucht ein Bild zu laden, dessen Thumbnail nicht mehr existiert. Zum Beispiel weil man gebeten wurde das Bild zu entfernen, auf die schnelle aber nur per FTP verbunden hat und dort auch zu allem Unglück nur den Thumbnail gelöscht hat, und nicht das vergrößerte Bild.

Das Fehlen von Dateien in einem Projekt, dass eigene Mechanismen zur Administration bietet, ist eine solche Exception. "Das sollte eigentlich nie passieren".

Nun stellt sich die Frage, wer fängt die Exception auf?
Tut es keiner, wird uns diese Arbeit die PHP-Engine abnehmen und einen Catchable Runtime Error liefern. Catchable!
Wir sollten das selber tun. Mehrere Kandidaten stehen zur Auswahl (in einem komplexeren System ungleich mehr):
die Bootstrap-Datei
das Gallery-Modul
die Image-Klasse (die das Bild laden soll)
das Ausgabe-Template?

Ist die Ausnahme so schwerwiegend, dass die Bootstrap-Datei über den Fehler informiert werden muss? Muss das Ausgabe-Template belästigt werden oder kann die Image-Klasse die Tragweite ihrer Handlung verstehen? Nein!
Das Gallery-Modul wird wohl am Besten wissen, was zu tun ist, zumal ihr der meiste Handlungsspielraum gegeben ist.
Sie kann den Fehler (das fehlende Bild)
überspringen
ihn ignorieren (Dead image link)
sie kann ein Standard-Bild laden
den Benutzer darüber informieren
oder sogar eine Kombination mehrerer

Wir müssen also darauf achten, Exceptions an der perfekten Stelle abzufangen, dort wo wir die Weitsicht besitzen, ihn angemessen zu verarbeiten.

Denn spielen wir das Szenario mal für den Fall durch, dass erst unsere Bootstrap-Datei den Fehler fängt:

Szenario 1:
Die Bootstrap wird vermutlich nurnoch dazu in der Lage sein eine Fehlermeldung zu schreiben und abzubrechen. Erinnern wir uns: Exceptions verlassen ihren Programmkontext bis zum nächsten catch! Wenn wir die Exception nicht früh genug abfangen wird der dahinterliegende Code überhaupt nicht mehr ausgeführt. Wir sind (ohne den Prozess neu anzustossen) garnicht mehr in der Lage die restlichen Bilder auszugeben!

Szenario 2:
Unsere Image-Klasse zum Laden der Grafik und Berechnen der Größe fängt ihren eigenen Fehler sofort auf:

Es könnte nur mit 2 Aktionen auf den Fehler reagieren:
Bild nicht anzeigen
Standardbild laden
Was aber, wenn wir dem Betrachter mit einer Nachricht mitteilen möchten, dass ein Bild nicht gefunden wurde, an einer Stelle, an der die Image-Klasse keinen Einfluß auf die Anzeige hat?


Das Gallery-Modul scheint also der richtige Ort zum Fangen dieser Exception zu sein!




Wie unterscheidet man Exceptions?

Es gibt viele verschiedene Variationen von Exceptions. Jede sollte in ihrem direkten Kontext schwer und von besonderer Bedeutung sein! Das heißt aber wie wir gesehen haben nicht unbedingt, dass sie in ihrer Gesamtheit betrachtet schwer sein muss.

Technisch lassen sich Exceptions über ihre Klasse oder ihren Exception-Code unterteilen.

Die Klasse "Exception" ist eine PHP interne Klasse. Von ihr kann abgeleitet werden (Stichwort Vererbung sollte für den Leser zumindest ein Begriff sein):

PHP-Code:
<?php
class My_Exception extends Exception
{
}
?>
Dies ist eine völlig akzeptable, lauffähige Klasse (besser gesagt Exception). Auch von ihr könnte nun abgeleitet werden:
PHP-Code:
<?php
class My_Stupid_Exception extends My_Exception
{
}
class 
My_Beloved_Exception extends My_Exception
{
}
?>
Diese Unterteilung ist sehr sinnvoll und erzeugt nur einen lächerlich geringen Overhead (der durch den Einsatz von __autoload sowieso in aberwitzige Dimensionen schrumpft).

Denkbar wären nun also
eine Bootstrap_Exception (Modul Gallery wird nicht gefunden, ..)
eine Gallery_Exception (keine Leserechte für den Bilderordner, aber eher nicht für den Fehlerfall, dass die angefragte Gallery silvester0607 nicht existiert, Verlinkungs- oder Copy&paste-Fehler treten ständig auf)
eine Image_Exception (siehe Beispiel)


Weiterhin ist es möglich, zusätzlich zur Message als 1. Parameter des Konstruktors, einen Fehlercode als 2. Parameter anzugeben. Dieser ist jedoch optional (Standard = 0):
PHP-Code:
<?php
throw new Image_Exception("thumbnail ist plötzlich weg"1);
?>
Schließlich könnte die Image-Klasse ja noch mehr Fehler werfen, zum Beispiel diesen:
PHP-Code:
<?php
throw new Image_Exception("hauptbild ist plötzlich weg"2);
?>
Es wäre nun möglich, die Fehler getrennt zu behandeln:
PHP-Code:
<?php
try {
  
$image = new Image($pfad_der_aus_der_datenbank_kommt);
  
$image->showThumbnail();
} catch (
Image_Exception $e) {
  if (
$e->getCode() == 1) {
     
// thumbnail ist offenbar weg, nicht so tragisch, nehmen wir
     // das große, html schrumpelt das schon kleiner
     // (natürlich bad-style, aber einfache beispiele erfordern das nunmal)
     
$image->setThumbnail($image->getBigImage());
     
$image->showThumbnail();
  }
  if (
$e->getCode() == 2) {
    
// ok das große Bild ist weg, was nun? am besten kein 
    // kleistern, einfach nur "oben" bescheid geben
    
$this->addMessage($e->getMessage()); // addMessage sei eine Methode des Gallery-Objektes, in dessen Kontext dieses Beispiel zu sehen ist
  
}
}
?>
"oben" sei in diesem Fall im Kontext des Gallery-Moduls zu sehen. Wir müssen uns vorstellen, dass dieser try-catch Block irgendwo im Bauch der Gallery-Klasse abläuft.

Etwas ist dem aufmerksamen Leser vielleicht aufgefallen:
Statt catch (Exception $e) wird plötzlich catch (Image_Exception $e) verwendet! Diese Notation, die übrigens seit PHP 5 auch für alle normalen Funktions und Methodendeklarationen erlaubt ist, schränkt den übergebenen Parameter auf ein Objekt der deklarierten Klasse (oder einer ihrer Ableitungen) ein.

Demnach fängt catch (Exception $e) alle in seinem try-Block gefangenen Exceptions ab, während catch (Image_Exception $e) nur mit throw new Image_Exception() erzeugte Exceptions abfängt (oder eben solche Exceptions, die von Image_Exception geerbt haben). Schließlich könnte die Image-Klasse ja auch einen kontextübergreifend-schweren Fehler werfen, von der sogar die Image-Klasse weiß, dass die Gallery hier nichts mehr retten kann/soll/darf. Zum Beispiel, wenn die Image-Klasse keine Grafik übergeben bekommt, sondern eine EXE-Datei (warum auch immer).

Natürlich darf die Image-Klasse keine Ueberspring_die_Gallery_Exception werfen, die Image-Klasse sollte soetwas nicht wissen müssen. Aber sie sollte die Möglichkeit haben auch derbere Ausnahmen auszulösen. Eine (nennen wir sie) System_Exception zum Beispiel.

Zur Verdeutlichung:
PHP-Code:
<?php
try {
  throw new 
Exception("mieser Fehler");
} catch (
Image_Exception $e) {
  echo 
$e->getMessage();
}
?>
Der catch-Block wird nie zur Ausführung kommen.




Wie fängt man mehrere Exceptions?

Ein Gallery-Modul muss ihre Aufgaben nicht nur an Image-Klassen weiterdelegieren. Der Einsatz vielerlei Klassen ist denkbar, sie müssten nicht einmal direkt etwas mit Bildern zu tun haben .. eine File-Klasse zum Zugriff auf Bilder wäre denkbar oder der Einsatz eines Log-Tools.

All diese Klassen können Ausnahmen erzeugen und viele von ihnen sollte vermutlich die Gallery abfangen, da es wohl niemanden außerhalb der Gallery interessiert, ob ein Bild nicht gefunden wurde oder eine Log-Datei nicht richtig funktioniert. Schon garnicht den Anwender.

Darum ist es möglich an einen try-Block mehrere catch-Blöcke anzuhängen, denen nacheinander versucht wird, die Exception zu übergeben. Hinweis: Der erste Treffer zählt, egal ob Ableitung oder direkt:

PHP-Code:
<?php
class My_Exception extends Exception
{
}
class 
My_Stupid_Exception extends My_Exception
{
}
class 
My_Never_Used_Exception extends Exception
{
}

try {
    throw new 
My_Stupid_Exception("ach wie blöd");
} catch (
My_Never_Used_Exception $e) {
    echo 
"My_Never_Used_Exception-Block: "$e->getMessage();
} catch (
My_Exception $e) {
    echo 
"My_Exception-Block: "$e->getMessage();
} catch (
My_Stupid_Exception $e) {
    echo 
"My_Stupid_Exception-Block: "$e->getMessage();
} catch (
Exception $e) {
    echo 
"Exception-Block: "$e->getMessage();
}
?>
Beachtet werden sollte, dass man nicht in den catch (My_Stupid_Exception $e) gelangt, obwohl eine Exception diesen Typs geworfen wurde, sondern catch (My_Exception $e), denn My_Stupid_Exception ist nach Deklaration ein Kind von My_Stupid_Exception.
Der erste Treffer zählt.




Wie wirft man eine Exception weiter?

Wenn der catch-Block (z.B. anhand des Exception-Codes) feststellt, dass das Problem doch lieber von einer höheren Instanz gelöst werden sollte oder gar durch seine Problemlösungsversuche selbst eine neue Exception auslöst, wird dies ganz "normal" gehandhabt, der nächsthöhere try-catch-Block fängt die Exception auf

Testen wir das ganze mit einer Fußballer-Weisheit, in dem unser innerer catch-Block die Exception einfach weiterschmeißt:
PHP-Code:
<?php
class My_Exception extends Exception
{
}
class 
My_Stupid_Exception extends My_Exception
{
}


try {
    try {
        throw new 
My_Stupid_Exception("ach wie blöd");
    } catch (
My_Exception $e) {
        echo 
".. nimm du ihn, ich hab ihn sicher .. ";
        throw 
$e;
    }
} catch (
My_Stupid_Exception $e) {
    echo 
"ich nehm ihn wohl besser";
}
?>
Die Ausgabe lautet, wie erwartet:
Code:
.. nimm du ihn, ich hab ihn sicher .. ich nehm ihn wohl besser
Hoffentlich konntet ihr einen kleinen Einblick in Exceptions bekommen und gebt eure Fehler nun nicht mehr nur durch return FALSE und Konsorten zurück, sondern lasst das die Exceptios erledigen. Dafür sind sie da.

Danke für eure Aufmerksamkeit!
Zergling-new ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 21.11.2007, 20:30  
Erfahrener Benutzer
 
Registriert seit: 17.06.2008
Beiträge: 125
squig befindet sich auf einem aufstrebenden Ast
Standard

Hola,

vll wäre noch interessant, welche Exceptions man loggt oder welche man "unter den Tisch kehrt".
Gibt es eigentlich in PHP auch das Konzept der "checked" und "unchecked" Exceptions? Sind mir nun in Java über den Weg gelaufen.

Freu mich auf die Lektüre.


Bis dääähne.
squig ist offline   Mit Zitat antworten
Alt 21.11.2007, 21:01  
Erfahrener Benutzer
 
Registriert seit: 16.07.2005
Beiträge: 1.007
PHP-Kenntnisse:
Fortgeschritten
brian johnson befindet sich auf einem aufstrebenden Ast
Standard

Wer/Was wirft exceptions
Warum/Wieso/Weshalb?

Zitat:
Gibt es eigentlich in PHP auch das Konzept der "checked" und "unchecked" Exceptions? Sind mir nun in Java über den Weg gelaufen.
nö, php kennt nur eine exception.
__________________
PHP4?!?>>>Aktuelle PHP Version: 5.2.11 || 5.3.0
Suse 11.2 *vorfreude*
brian johnson ist offline   Mit Zitat antworten
Alt 22.11.2007, 02:45  
Erfahrener Benutzer
 
Registriert seit: 21.05.2008
Beiträge: 9.937
Zergling-new wird schon bald berühmt werden
Standard

Zitat:
Zitat von squig
vll wäre noch interessant, welche Exceptions man loggt oder welche man "unter den Tisch kehrt".
Gibt es eigentlich in PHP auch das Konzept der "checked" und "unchecked" Exceptions? Sind mir nun in Java über den Weg gelaufen.
checked unchecked kenne ich selbst nicht, was man loggt und nicht loggt ist glaube ich die Ermeßenssache.
Zergling-new ist offline   Mit Zitat antworten
Alt 05.12.2007, 23:31  
Erfahrener Benutzer
 
Registriert seit: 17.01.2006
Beiträge: 468
Slava
Standard

Zitat:
Gibt es eigentlich in PHP auch das Konzept der "checked" und "unchecked" Exceptions?
begriffe 'checked' und 'unchecked' Exceptionen sind wirklich bei Java vorhanden, wobei unchecked Exceptionen keine Möglichkeit von abfangen haben.
Wenn du in PHP ein brutaler fehler machst, dann bekommst du auch eine art von unchecked Exception, die zwar keine Exception sondern Fatall Error bedeutet.
An dieser stelle spielt es keine rolle, ob es "unchecked Exception" oder "Fatal Error" heist, der Fehler lässt sich einfach zur laufzeit nicht mehr beheben (egal, ob das java oder php ist)
__________________
Slava
http://bituniverse.com
Slava ist offline   Mit Zitat antworten
Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

LinkBacks (?)
LinkBack to this Thread: http://www.php.de/tutorials/45124-php-exceptions-teil-1-a.html
Erstellt von For Type Datum
SELFHTML Forumsarchiv / 2011 / Mai / OOP php: verschachtelte Klassen und ein Zugriff auf eine Eigensc This thread Refback 12.02.2012 10:56
Exceptions und Exceptionhandler - PHP - DeveloperTalk This thread Refback 19.09.2011 19:33
SELFHTML Forum: (PHP) OOP php: verschachtelte Klassen und ein Zugriff auf eine Eigensc This thread Refback 07.06.2011 10:05
CMSimple XH mod g-com.eu - Auch ein Alf der muss mal meckern! - Meckerecke This thread Refback 04.02.2010 15:17
spezo's tutorial Bookmarks on Delicious This thread Refback 17.12.2008 14:40

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
PHP: Exceptions - Teil 2 Zergling-new Tutorials 5 15.03.2009 11:00
JavaScript/PHP: qooxdoo 0.7.1 - Teil 1 : Eine Einführung Zergling-new Tutorials 6 25.01.2008 10:41
PHP-Errors zu exceptions brian johnson PHP-Fortgeschrittene 6 06.11.2007 12:45
Teil einer Variablen mit einer Variablen ersetzen ? simsalabim PHP Tipps 2007 11 20.03.2007 20:36
include, nur bestimmten teil neu laden Calli PHP Tipps 2006 2 27.01.2006 15:57
erbende Exceptions mit PHP 5.1.1 nicht mehr möglich? HStev PHP-Fortgeschrittene 4 27.01.2006 14:32
den buchstaben teil ermitteln Dilandau PHP Tipps 2006 2 25.01.2006 16:49
PHP-GTK Tutorial Beitragsarchiv 9 02.11.2005 21:07
nur bestimmten teil von php anzeigen se-clan PHP Tipps 2007 6 31.10.2005 20:52
[Erledigt] Nur Teil von Zelle auslesen Datenbanken 7 16.09.2005 13:38
Immer nur der erste Teil der if-Abfrage? JonathanArcher PHP Tipps 2005-2 5 04.06.2005 14:28
teil eines strings ausschneiden janni PHP Tipps 2007 6 03.01.2005 14:21
Fehler im BETWEEN Teil? R4v3r Datenbanken 4 22.11.2004 19:42
makierten teil herausfinden Filewalker PHP Tipps 2004 5 18.10.2004 22:28

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
php exception, php exceptions, exception php, php exceptions tutorial, php exception tutorial, php exception abfangen, exceptions php, php eigene exception, php eigene exceptions, php exeptions, eigene exception php, php exception ausgeben, php exceptions example, php try catch tutorial, php error exception, php fehler werfen, php exception auslösen, php exeption, exception abfangen php, exceptions in php

Alle Zeitangaben in WEZ +2. Es ist jetzt 02:17 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum

Creative Commons License
Dieser Inhalt ist unter einer Creative Commons-Lizenz lizenziert.