Andreas Korthaus: komplexes Error-Handling

Hallo!

Ich habe mich zwar schon hier udn da mit Error-Handling beschäftigt, aber immer nur für kleine Teile eines Projektes, udn nie in letzter Konsequenz. Jetzt plane ich ja ien Projekt mit modularer Struktur:

alle HTTP-Requests werden auf ein zenrales PHP-Script umgeleitet(index.php).
Dieses Script läd alle Conf Daten ud Module, und reagiert auf den Request in dem es das entsprechende Script für die Ausgabe läd, die dann mit Hilfe von Smarty-Templates generiert wird.

Jetzt überlege ich wie ich ein zenttrales Error-Handling  Objekt einbinden könnte. Dazu habe ich mir PEAR::isError() ausgeguckt(http://pear.php.net/manual/en/class.pear.php), da ich davon viel Gutes gehört habe und mir sicher bin das ich es selbst in annehmbarer Zeit nicht besser hinbekommen würde.

Ich habe folgende Arten von Fehlern:

  • HTTP Fehler(404...)
  • PHP-Fehler(bei Funktionen wie mail()...)
  • PEAR Fehler(PEAR:DB)
  • SMARTY Fehler
  • Anwendungs-Fehler(Fehler im Programm, wenn bestimte Aktion nicht wie erwartet ausgeführt werden kann)
  • Eingabe-Fehler (Formular-Überprüfung)

Folgende Behandlungen der Fehler habe ich vorgesehen:

  • Loggen normaler Fehler
  • Email-Benachrichtigung über schwere Fehler
  • verschiedene Augabe der Fehler(Javascript, HTML-Ausgabe)

Das ganze muß ich überall einbetten können, in Klassen, Funktionen und in normalen Code. Erschwerend kommt hinzu das die Fehlerausgabe mehrsprachig erfolgen soll.

Soweit ich PEAR jetzt verstanden haben muß ich mir für alle Fehlerarten eine eigene Callback-Funktion schreiben, die ich dann ggfs aufrufen kann. z.B. für HTTP-Fehler eine Funktion die eine Fehlerseite erzeugt und für die Logs einen HTTP-Error Header sendet.
Für PHP-Funktionen muß ich dann auch jedesmal eine if-Abfrage machen ob die Funktion funktioniert hat und sonst meine Call-Back-Funktion aufrufen.
Problematischer wird die Sache bei Smarty, das hat ja einen eigenen Error-Handler, wie kann ich das am besten mit meinem Handler in Einklang bringen?
Doof ist das auch mit Klassen, muß ich dann jede Klasse als Erweiterung der PEAR-Klasse schreiben? (... extends PEAR)
Udn was ist mit der Überprüfung der Userdaten? Hat das Sinn auch hir PEAR zu verwenden? Denn das ganz eist ja doch immr individuell  udn ich muß ja darauf reagieren. Bisher habe ich das immer so gemacht:

if(!is_valid($_GET["name"])) {
    $errors[] = "blabla";
}
if(!is_valid($_GET["ort"])) {
    $errors[] = "blabla";
}
if(!is_valid($_GET["lieblingsTVserie"])) {
    $errors[] = "blabla";
}
if ($errors) {
echo implode("<br>",$errors);
}
else {
//starte Aktionen
header("Location:...");
}

Wie macht man das sinnvollerweise mit PEAR?

Und noch eine (peinliche) Frage:
Wohin schreibe ich meien Error_callback Funktionen? Ganz einfach irgendwo in das Script, doer kannich dafür nicht eine eigene Klasse mit entsprechenden Methoden verwenden?

Bin für jeden Tipp sehr dankbar, vielleicht hat hier ja jemand Erfahrung mit der PEAR Error-Klasse.

Vielen Dank im voraus und viele Grüße,
Andreas

  1. Hi,
    ich kann dir hier keine vollstaendige Loesung geben, aber ein paar kleine Steine aus dem Weg raeumen.

    Jetzt überlege ich wie ich ein zenttrales Error-Handling  Objekt einbinden könnte. Dazu habe ich mir PEAR::isError() ausgeguckt(http://pear.php.net/manual/en/class.pear.php), da ich davon viel Gutes gehört habe und mir sicher bin das ich es selbst in annehmbarer Zeit nicht besser hinbekommen würde.

    sehr loeblich, PEAR ist einfach zu gut um ignoriert zu werden.

    Soweit ich PEAR jetzt verstanden haben muß ich mir für alle Fehlerarten eine eigene Callback-Funktion schreiben, die ich dann ggfs aufrufen kann. z.B. für HTTP-Fehler eine Funktion die eine Fehlerseite erzeugt und für die Logs einen HTTP-Error Header sendet.

    genau.

    Für PHP-Funktionen muß ich dann auch jedesmal eine if-Abfrage machen ob die Funktion funktioniert hat und sonst meine Call-Back-Funktion aufrufen.

    nein, wenn deine funktion nicht funktioniert ein PEAR::raiseError() absetzten, oder deine funktionen im fehlerfall ein PEAR::Error objekt zurueckgebenlassen und das mit PEAR::isError testen.

    Problematischer wird die Sache bei Smarty, das hat ja einen eigenen Error-Handler, wie kann ich das am besten mit meinem Handler in Einklang bringen?

    ich kenne den smartyhandler jetzt nicht aber kannst du nicht 'wenn smarty fehler, dann PEAR error raisen' irgendwo einbauen?

    Doof ist das auch mit Klassen, muß ich dann jede Klasse als Erweiterung der PEAR-Klasse schreiben? (... extends PEAR)

    nein, nur wenn du innerhalb der klasse ein objekt (klasseninstanz) gebundenes error objekt behandelt willst. (a la $this->raiseError()) anderfalls reicht ein statischer aufruf mit PEAR::raiseError() (PEAR.php muss natuerlich vorher eingefuegt werden)

    Wie macht man das sinnvollerweise mit PEAR?

    ich wuerde mir jetzt die isValid() funktion so implementieren, dass sie im falle eines fehlers ein error objekt zurueckgibt

    $res = isValid($FOO);
    if(PEAR::isError($res) { ... }

    Und noch eine (peinliche) Frage:
    Wohin schreibe ich meien Error_callback Funktionen? Ganz einfach irgendwo in das Script, doer kannich dafür nicht eine eigene Klasse mit entsprechenden Methoden verwenden?

    du kannst auch eine klasse bzw. ein objekt verwenden. statt des funktionsnamens gibst du einfach ein array('klassenname', 'methodenname') oder array($objekt, 'methodenname') an.

    Jan
    --

    1. Hallo!

      sehr loeblich, PEAR ist einfach zu gut um ignoriert zu werden.

      Finde ich auch. Aber was macht das eigentlich aus von wegen Performance wenn ich immer eine so große Klasse einbinde? Habe weiter unten einen Thread([pref:t=33948&m=184917] ff.) wegen eines sehr komplexen modular aufgebauten PHP-Projektes(um das es auch hier geht) eröffnet und dort die Frage gestellt, wie das aussieht wenn ich im Gegensatz zu einem einfachen Script mit 100 Zeilen die nötig wären aufgrund der modularen Struktur immer erste mein komplettes Basismodul, notwendige Zusatzmodule, PEAR, SMARTY, Templates, Language-Files... lade, wie wirkt sich das in der Praxis aus, wird das ganze dadurch dann nicht _erheblich_ langsamer?  Und kann man in PHP irgendwie ermitteln, wieviel Code insgesamt bei einem Scriptaufruf ausgeführt bzw. geparst wird?

      ich kenne den smartyhandler jetzt nicht aber kannst du nicht 'wenn smarty fehler, dann PEAR error raisen' irgendwo einbauen?

      Mal schaun, ich guck mir das mal an und wenn ich nicht weiterkomme frage ich mal in der Mailingliste, da werde ich wohl nicht der einzige sein mit diesem Problem. Wäre schon gut wenn das möglich ist!

      Wie macht man das sinnvollerweise mit PEAR?
      ich wuerde mir jetzt die isValid() funktion so implementieren, dass sie im falle eines fehlers ein error objekt zurueckgibt

      $res = isValid($FOO);
      if(PEAR::isError($res) { ... }

      Wenn ich aber 20 derartige Anfragen habe will ich nur prüfen ob überhaupt ein Fehler aufgetreten ist oder nicht. Wenn ein oder mehr Fehler aufgetreten sind, will ich eine entsprechende Message ausgeben.

      Danke für die kompetente Hilfe ("@php.net", das hatte ich hier noch nicht ;-)).

      Viele Grüße
      Andreas

      PS: soll nicht heißen das ich hier sonst keine kompetente Hilfe bekomme - ganz im Gegenteil!