PHP-Logo
Druckansicht von http://www.php-homepage.de/artikel/artikel7.html

PHP-Logo
[ Main Menue ]
Homepage
Downloads
Artikel
Scripts
Forum
PHP-Manual
Links
News
Freelancer
Bücher
RuDolF
Suche
Misc
Über diese Seite
Kontakt
Wunschzettel
MyGuestbook
*
[ Suche ]
*
[ Partner ]


Domain Webhosting
*
[ Partner Sites ]
Dynamic-Webpages
PHP-Center
PHP-Welt
phpUG.de
Random Link
*
[ Autoren gesucht! ]
PHP-Homepage.de sucht laufend Autoren für News und Artikel
Interesse?
*

Follow on Twitter - @phphomepage

RSS Feed blogoscoop

Fehlerbehandlung bei grossen PHP Projekten von Thomas Fromm

Jeder kennt das Problem, es gibt nicht nur Syntaxfehler, sondern auch Fehler, die durch Fehleingaben und technische Unzulänglichkeiten (Verbindungsabbrüche usw.) entstehen und in den meisten Fällen zur Laufzeit des Programmes auftreten. Für Anwender und Entwickler ist dies eine Störquelle, welche beim einen für Unverständnis des Auftretens und beim anderen für Schwierigkeiten bei der Behebung sorgt, da bestimmte Zustände wieder hergestellt werden müssen um diesen Fehler zu replizieren.

Als erstes ist es wichtig, dass der Anwender keine Fehlermeldungen zu Gesicht bekommt bzw. nur in einer "hübschen" Form. Ein einfaches @ vor der jeweiligen Funktion oder Befehl. Die Fehlerausgabe kann unterdrückt werden damit.

Ein einfaches Beispiel: Eine Variable deren Inhalt eigentlich ein Array sein sollte wird benutzt, jedoch beinhaltet sie aufgrund eines Fehlers ein String.

$value="x";

Der Aufruf mit 
current($value);

erzeugt eine Fehlerausgabe: Warning: Variable passed to current() is not an array or object in ...

Wir unterdrücken diese Ausgabe mit einem @.

@current($value);

Das Problem ist aber jetzt, das es schwer wird den Fehler zu finden. Nun ist es möglich das Auftreten eines Fehlers mit or die() abzufangen und somit sichtbar zu machen.

@current($value) or die("Ein Fehler ist aufgetreten."); Die nun erfolgende Textausgabe ist zwar hübscher, bringt uns aber nicht sehr viel weiter. Um mehr Flexibilität zu haben schreiben wir uns am besten eine Funktion, die das die() ersetzt und uns mehr Informationen liefert und nicht gleich das Skript abbricht. Wir nennen sie mal debug(); Selbst wenn die Funktion ein "reguläres" false zurückliefert (z.B. is_array($values)) kann die() oder unsere spätere Funktion genutzt werden.

Wir müssen dieser Funktion natürlich einige Informationen übergeben damit diese dann entsprechend reagieren kann und wir müssen uns auch ein paar Parameter einfallen lassen, denn im Betrieb soll diese Funktion etwas anders reagieren als während der Entwicklungszeit.

$print_error=TRUE; // wird auf TRUE gesetzt, wenn der Fehler direkt auf dem 
		   // Bildschirm ausgegeben werden soll (für Entwickler)
		   // andernfalls auf FALSE
$debug_level=3; // dient zur Steuerung ab welchen Level die Fehler ausgegeben
		// werden sollen (dazu später mehr)

Jetzt müssen wir nur noch wissen wo und wann dieser Fehler auftrat.

Zum Einsatz kommen zwei Konstanten, welche einige bestimmt aus der C-Welt kennen, und im PHP Manual dokumentiert sind.

__LINE__ ist gesetzt auf die aktuelle Zeile

__FILE__ ist gesetzt auf den aktuellen Pfad der Datei

Da Fehler ungleich Fehler ist und ein Auftreten nicht unbedingt gleich den Abbruch der Skriptes erfordert ist es ratsam eine Art Fehlerlevel festzulegen. Hier unterscheiden wir nur zwischen Ausgaben die als Programmierhilfe dienen auch ohne das Fehler auftreten (Level 3). Fehler, die wenn sie auftreten zwar bestimmte Funktionen beeinträchtigen, aber den Ablauf des Gesamtskripts nicht gefährden (Level 2) und Fehler, die sehr schwer wiegen und möglicherweise Sicherheit oder Ablauf des Skriptes ganz unmöglich gestalten (Level 1). Dies ist nur eine grobe Einteilung

Jetzt bauen wir mal die Funktion debug. Der Aufruf der Funktion kann so gestaltet werden: (der Fehler ist jetzt mal leichter Natur)

is_array($value) or debug(2,__LINE__,__FILE__,"Variable value : Das Array ist Fehlerhaft");

und normale Ausgaben als Programmierhilfe:

debug(3,__LINE__,__FILE__,"Elemente im Array".count($value));

Wenn jemand den print_error auf FALSE setzt muss je ein Logfile erzeugt werden: (Hinweis: Das Logfile sollte bereits existieren und der Webserver muss Schreibzugriff haben (z.B. (unter unix/linux)

touch debuglog
chown nobody.nogroup # der Webserver läuft meist als nobody )
 
function debug_log($debugstring){
        if (file_exists("debuglog")){
            $fp=fopen("debuglog","a");
            fwrite($fp,$debugstring);
            fclose($fp);
        }        
}

function debug($errorlevel,$line,$file,$textstring){
   // wir holen die Einstellungen für die Ausgabe in die Funktion
   global $print_error;
   // je nach einstellung werden alle ausgaben oder erst ab einem bestimmten
   // errorlevel ausgegeben
   global $debug_level;
   // damit der Zeitpunkt des Auftretens festgehalten wird
   $errortime=date("d.m.y G:i:s", time());
   // jetzt wird der Fehlerstring zusammengesetzt
   $errorstring="\n".$errorlevel." ".$errortime." ".$file." ".$line." ".$textstring;
   // unterschiedliche Farben machen die Ausgabe besser deutlich
   if($errorlevel==1 && $debug_level>=1){
	if ($print_error){
	   echo ">P<>FONT SIZE=-1 COLOR=\"#FFOO00\"<".$errorstring.">/FONT<</P<";
	} else {
	   debug_log($errorstring);
	}
	die(); // fehler ist ja schwerwiegend
   } elseif ($errorlevel==2 && $debug_level>=2){
	if ($print_error){
	   echo ">P<>FONT SIZE=-1 COLOR=\"#0000FF\"<".$errorstring.">/FONT<>/P<";
	} else {
	   debug_log($errorstring);
	}
   } else {
	if ($print_error){
	   echo ">P<<FONT SIZE=-1 COLOR=\"#00FF00\"<".$errorstring.">/FONT<>/P<";
	} else {
	   debug_log($errorstring);
	}
   } 
}

Datenbank Fehler treten sehr häufig auf. Damit wir eine gute Ausgabe erzeugen verwenden wir ebenfalls eine kleine Funktion. Hier Oracle:

$type beinhaltet den Typ entweder ein Statement, eine Verbindung usw. oder wenn sie leergelassen wird, wird der zuletzt auftretende Fehler genommen.

function database_debug($type,$query="Connection"){
        $error=@OCIError($type);
        $errorstring=sprintf("OCIError: %s %s Query: %s",
                             $error["code"],
                             $error["message"],
                             $query);
        return $errorstring;
}

Der Aufruf ist dann in der Art:

$query="INSERT INTO test (id,text) VALUES ('55','Testtext')";
$stmt=@ociparse($conn,$query)
	       or debug(1,__LINE__,__FILE__,database_debug($stmt,$query);

Diese Funktion kann nun verwendet werden. Dabei ist auf eine sinnige Verwendung zu achten, jeden Befehl damit zu Bestücken bläht den Quellcode auf.

Wichtig ist, dass der Text, der übergeben wird als Hilfsmittel zu gebrauchen ist. Texte wie "Alles ok" sind also zu vermeiden. Diese Funktion kann beliebig erweitert werden, z.B. verwendet man Sessions, koennen in diesen zu jedem User "einzeln" bestimmte Einstellungen gespeichert werden. Es kann der Pfad zum Logfile in der Session gespeichert werden, die Einstellungen bis zu welchem Level gelogt wird oder wohin die Mitteilungen geschrieben werden sollen und somit separat gelogt werden.

Wird neben dem Text noch die entsprechende Userid oder spezielle Kennung für die jeweilige Webseite, kann man einzelne Benutzer "isolieren" und durch das System verfolgen. (Usertracking)

Ist die Zeit knapp Logfiles zu studieren, so können auch durch die Verwendung von der allseits beliebten mail() Funktion schwerwiegende Fehler direkt versand werden.

Ich hoffe dieser Artikel gibt dem einen oder anderen etwas Inspriration und hilft bei der Verwirklichung grösserer Projekte. Ich bedanke mich für das Interesse.

Über den Autor: Thomas Fromm ist Student an der Universität Potsdam und bewegt sich seit seit 1999 verstärkt in der PHP Scene. Neben einigen anderen Projekten gilt seine Aufmerksamkeit besonders der Firma InUBIT(www.inubit.com) in Berlin, wo er als Mitarbeiter an der Entwicklung anspruchsvoller B2B-Marktplatzlösungen auf der Basis von PHP und anderen Technologien mitwirkt.


Zurück zur Übersicht
© Copyright 1999 - 2011 by Mark Kronsbein | Impressum | NutzungsbedingungenWeiterempfehlen | Seitenanfang
0.0227