Philipp Hasenfratz: OOP Error-/ExceptionHandling

Beitrag lesen

Halihallo Christian

noch nichts von SIG__DIE__ gehört? :) Ich persönlich arbeite viel so:

Die Idee ist wirklich sehr gut, nur bei der Umsetzung in einem OOP-
Kontext habe ich einige kleine Bedenken (die Vorteile überwiegen
jedoch).

Geht eigentlich recht angenehm und braucht nicht diese ekeligen
eval-Konstrukte. Du kannst $SIG{__DIE__} sogar lokal überschreiben:

Deine Lösung umgesetzt, würde in etwa folgendes Konstrukt als Äquivalent für try-catch-finally vorsehen:

sub doSomething($) {
   my ($self) = @_;
   local $SIG{__DIE__} = sub { $self->classErrorHandler(@_); }
   # do whatever throws probabely an exception...
}

sub classErrorHandler($$) {
  my ($self,$error_message) = @_;
  # do something with $error_message
}

oder aber:

sub doSomething($) {
   my ($self) = @_;
   local $SIG{__DIE__} = sub {
      my ($err) = @_;
      print($err->getErrorDesc() . ' at line: '.$err->getLine());
      exit(255);
   }
   # do whatever throws probabely an exception... eg:
   die( new Error('ERR_NO_VALID_CHARACTER', 'ä ist ungültig') );
}

Randbemerkung: Das ErrorHandling operiert nicht ausschliesslich im
package main, sondern auf Objects und Klassen. Deshalb machen
allgemeine (globale, staatische Funktionsaufrufe) Konstrukte wie $SIG
{__DIE__} = &fatal; wenig Sinn; aber das Umsetzen in OOP kannst du
ja ruhig mir überlassen :-)

Hm. Die zweite Version wirft nicht wesentlich mehr Overhead für das
ErrorHandling auf. Was mich daran etwas stört ist
a) das ErrorHandling wird *vor* dem eigentlichen Fehlerverursacher
   definiert. Dies halte ich für Verwirrend und unschön. Der
   Programmfluss wird "verschleiert" und verschlechtert die
   Lesbarkeit des Codes.
b) Signale dieser Art haben in OOP absolut nichts zu suchen; jedoch
   ist dein Vorschlag einem eval-Konstrukt dennoch vorzuziehen.
c) in der ersten Version braucht man eine separate Klassenmethode
   für das ErrorHandling, aber verschiedene Methoden brauchen u.U.
   auch verschiedene Verarbeitungsvorschriften für die Exceptions.
   Natürlich könnte man jeweils den Methodennamen als Parameter
   übergeben, oder caller() auswerten, jedoch ist dies viel zu viel
   Overhead.
   Oder man schreibt für jede Methode eine eigene ErrorHandler-
   Methode, was jedoch viel zu viel Overhead bedeutet.
   => die erste Version ist untragbar.

Was ich an dieser Lösung sehr schön finde ist:
a) Es ist ziemlich einfach und universell.
b) Es generiert nicht allzuviel Overhead (Tipparbeit)
c) der Signalhandler wird trotz umschreiben des Signals automatisch
   wiederhergestellt, der Programmfluss ist also "stabil". Thanks
   to local. Alles andere wäre böse[tm].
d) kein böses eval
e) Das local $SIG{__DIE__} Verfahren ist selbst bei verschachtelten
   Aufrufen noch korrekt, da der Kontext der Fehlerbehandlung im
   Methoden-Scope stattfindet. Alles andere wäre böse[tm].

Ich hoffe, das hilft. Vorsicht aber: auch in eval()-Blöcken wird
der Callback von die() ausgeführt! Als ggf. überschreiben per local.

Wieso? - Ich zähle sogar darauf, dass er ausgeführt wird, ansonsten
sehe ich die Fehlermeldung nicht...

-------------

Vielen Dank Christian, das war wirklich ein sehr interessanter und
guter Vorschlag! - Obgleich unschön... Aber das hängt nicht an uns,
sondern an Perl, leider...

Viele Grüsse

Philipp