php.de

Zurück   php.de > Webentwicklung > PHP Einsteiger > PHP Tipps 2007

 
 
LinkBack Themen-Optionen Thema bewerten
Alt 10.08.2007, 01:25  
Neuer Benutzer
 
Registriert seit: 10.08.2007
Beiträge: 12
qwertzu
Standard Errorhandling mit PHP 5

Hallo,

benutzt ihr Errorhandler? Ich habe eine Errorhandler-Klasse, welche von allen Projekten verwenden werden soll, indem ich diese Klasse über eine weitere Klasse erweitere (...extends...), um projektspezifische Meldungen zu handlen. Ich weiß aber noch nicht, wie ich das am besten löse. Habe schon alle Contributions auf php.net zu dem Thema durchgearbeitet, aber keine hat mir dabei weiterhelfen können. Das Problem ist, dass ich die Fehlermeldung gleichzeitig mit trigger_error() werfen möchte und nicht an die projektspezifische Klasse, sodass das Script auch funktioniert, wenn diese Klasse nicht eingebunden ist. Es sollen auch Fehlermeldungen, die von PHP geworfen werden, abgefangen werden, dafür verwende ich set_error_handler(); An trigger_errors zweiten Parameter kann man einen eigenen Typen übergeben. Anstatt der Konstante E_USER_ERROR, z. B. E_MYSQLCLASS_ARGUMENT_ERROR oder E_MYSQLCLASS_SQL_MALFORMED. Die abgeleitete Klasse enthält dann einen Array, welcher diese ganzen Typen enthält dementsprechend auf Warnungen und Fehlermeldungen reagiert. Was haltet ihr von der Methode bzw. wie verwendet ihr Errorhandler in euren Projekten?

Vielen Dank im Voraus für eure Antworten!

Gruß
Tim
__________________
Betriebssystem: Ubuntu 7.10, Kernel v2.6.24-8-generic
Webserver: LightTPD v1.4.13, PHP v5.2.4 + FastCGI + MySQLi v5.0.51a
qwertzu ist offline  
Sponsor Mitteilung
PHP Code Flüsterer

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

Alt 10.08.2007, 02:48  
Erfahrener Benutzer
 
Registriert seit: 21.05.2008
Beiträge: 9.937
Zergling-new wird schon bald berühmt werden
Standard

Hallo,
erstmal noch ein herzliches Willkommen hier im Forum! Zu deinen Konsolen-Fragen kann ich dir leider keine Antwort geben, da habe ich selbst kaum Ahnung. Obwohl ich zufällig gerade selbst am Schreiben eines kleinens CLI-Skriptes bin.
Zum Thema:

trigger_error() habe ich bis vor einiger Zeit auch benutzt, hauptsächlich um wirkliche Skript-Fehler aufzudecken, das heißt fehlerhafte Parameter-Typen bei Funktions-/Methodenaufrufen. Mit PHP 5 kommt da ja Typehinting ins Spiel, sehr angenehm und Exceptions.

Ich finde Exceptions angenehmer als mit dem Error-Handler von PHP herumzuspielen, denn du kannst das Problem da versuchen zu lösen, wo du es lösen kannst oder möchtest. Wo heißt in dem Fall in der Abstraktionsstufe deiner Wahl. Bedarfsweise innerhalb der Klasse oder aber ganz "außen".

Der Error-Handler springt ja aus dem Skript raus - und soweit ich mich richtig erinnere - auch wieder zurück, wenn du ihn nicht explizit beendest, aber du verläßt ja trotzdem den Kontext. Zugriff auf die Klasse, in der zum Beispiel ein Fehler erfolgt ist, hast du dann nicht mehr.

Ich sehe das letztlich so:
trigger_error mehr für technische Fehler/Warnungen/Hinweise, das heißt, die dem Programmierer zeigen sollen, dass er hier nicht ganz sauber gearbeitet hat.
Exceptions dafür mehr um vom User verursachte Fehler abzufangen (hochgeladenes Bild kann nicht kopiert werden, oder weiß der Geier was für Mißzustände ein Benutzer unbewußt verursachen kann).

Aber letztlich bleibts doch Geschmackssache, nur warum Exceptions nicht verwenden, wenn sie doch genau dafür da sind: Den Fehler da zu behandeln wo man es möchte, anstatt Rückgabewerte zu mißbrauchen (oder den Error-Handler von PHP ).

Gute Nacht
Zergling-new ist offline  
Alt 10.08.2007, 12:38  
Erfahrener Benutzer
 
Registriert seit: 21.07.2005
Beiträge: 209
pepe24
Standard

Hallo,

Zitat:
benutzt ihr Errorhandler?
Ähem... ja?!

Da muss ich Zergling zustimmen. Wieso keine Exceptions verwenden? Dafür gibt
es meiner Ansicht nach keine Argumentation... Mit Exceptions ist PHP um ein
mächtiges Feature erweitert worden.

Die Exception Klasse bringt schon in der Grundform Methoden mit, die dir viel
arbeit und zeit ersparen können.
Nicht aufgefangene Fehler kannst du Hierarchisch nach "oben" weiterreichen, um
sie zu fangen.

Zitat:
Ich sehe das letztlich so:
trigger_error mehr für technische Fehler/Warnungen/Hinweise, das heißt, die dem Programmierer zeigen sollen, dass er hier nicht ganz sauber gearbeitet hat.
Exceptions dafür mehr um vom User verursachte Fehler abzufangen (hochgeladenes Bild kann nicht kopiert werden, oder weiß der Geier was für Mißzustände ein Benutzer unbewußt verursachen kann).
Da muss ich widersprechen. Wenn man schon Exceptions benutzt, dann richtig und vollständig. Wieso noch einen zweiten, anders strukturierten/ arbeitenden Error-Handler mit ins Spiel bringen? Das macht die Sache doch unnötig komplizierter: Wenn nun ein anderer Entwickler an dem Projekt weiterarbeitet, steigt er zu 100% nicht durch solch eine Struktur durch.

Gruß
pepe24 ist offline  
Alt 10.08.2007, 14:06  
Erfahrener Benutzer
 
Benutzerbild von phpdummi
 
Registriert seit: 06.06.2008
Beiträge: 1.631
PHP-Kenntnisse:
Anfänger
phpdummi ist zur Zeit noch ein unbeschriebenes Blatt
Standard

Hallo,

vielleicht wurde auch übersehen, dass in einem Try-Block durchaus mehrere verschiedene Exceptions herumfliegen können.
PHP-Code:
<?php
class File {  
  ...
  function 
copy($to) {
    if (!
copy($this->path$to)) {
    throw new 
IOException("Could not copy file!");
    }
  }
  ...
}

class 
Project {
  ...
  function 
setup(File $template) {    
    
$template->copy($this->projectPath);
    
$this->initialize();
  }
  ...
}

class 
CreateProjectAction {
  ...
  function 
main(Request $r) {   
    try {
      
$tpl = new Template($r->getParam('type'));
      
$p = new Project();
      
$p->setup($tpl);
    } catch (
Exception $e) {
      
$this->log($e);
    }
  }
  
//...
}
?>
Mehr dazu *hier* und an vielen anderen Stellen im Netz.
Eigene Exceptions:
PHP-Code:
<?php
class Exception
{
   protected 
$message 'Unknown exception';  // Ausnahmemitteilung
   
protected $code 0;                        // Benutzerdefinierter Code
   
protected $file;                            // Quelldateiname der Ausnahme
   
protected $line;                            // Quelldateizeile der Ausnahme

   
function __construct($message null$code 0);

   final function 
getMessage();                // Mitteilung der Ausnahme
   
final function getCode();                  // Code der Ausnahme
   
final function getFile();                  // Quelldateiname
   
final function getLine();                  // Quelldateizeile
   
final function getTrace();                  // Array mit Ablaufverfolgung
   
final function getTraceAsString();          // Formatierter String mit
                                               //  Ablaufverfolgung

   /* Überschreibbar */
   
function __toString();                      // Formatierter String für
                                                 //  Ausgabe
}
?>
(Quelle: dynamicwebpages.de)
__________________
"Nobody is as smart as everybody" - Kevin Kelly
— The best things in life aren't things
phpdummi ist offline  
Alt 10.08.2007, 22:31  
Neuer Benutzer
 
Registriert seit: 10.08.2007
Beiträge: 12
qwertzu
Standard

Hallo,

Zitat:
erstmal noch ein herzliches Willkommen hier im Forum!
Vielen Dank!

Zitat:
Zu deinen Konsolen-Fragen kann ich dir leider keine Antwort geben, da habe ich selbst kaum Ahnung. Obwohl ich zufällig gerade selbst am Schreiben eines kleinens CLI-Skriptes bin.
Interessant. Was für ein Konsolenscript schreibst du? Für Windows?

Zitat:
Mit PHP 5 kommt da ja Typehinting ins Spiel
Gute Idee. Warum funktioniert Type Hinting nicht mit Strings oder Integers?

Zitat:
Ich finde Exceptions angenehmer als mit dem Error-Handler von PHP herumzuspielen, denn du kannst das Problem da versuchen zu lösen, wo du es lösen kannst oder möchtest.
Ja, sehe ich auch so. Aber wie löst du es, wenn während im Produktionsmodus ein Fehler auftritt? Auf jeden Ausdruck, der möglicherweise einen Fehler erzeugen könnte eine try..catch anzuwenden ist nicht sehr sinnvoll.

Zitat:
Wo heißt in dem Fall in der Abstraktionsstufe deiner Wahl. Bedarfsweise innerhalb der Klasse oder aber ganz "außen".
Das verstehe ich nicht genau.

Zitat:
Der Error-Handler springt ja aus dem Skript raus - und soweit ich mich richtig erinnere - auch wieder zurück, wenn du ihn nicht explizit beendest, aber du verläßt ja trotzdem den Kontext. Zugriff auf die Klasse, in der zum Beispiel ein Fehler erfolgt ist, hast du dann nicht mehr.
Wenn man den Fehler nicht "behandelt" (try..catch), bricht das Script mit einer Fehlermeldung ab. Warum ist kein Zugriff auf die Klasse möglich, wenn der Fehler verarbeitet worden ist? Wird unset() (+ __destruct()) nach jeder Exception aufgerufen?

Zitat:
trigger_error mehr für technische Fehler/Warnungen/Hinweise, das heißt, die dem Programmierer zeigen sollen, dass er hier nicht ganz sauber gearbeitet hat.
z. B. falscher Datentyp, etc.?

Zitat:
Exceptions dafür mehr um vom User verursachte Fehler abzufangen (hochgeladenes Bild kann nicht kopiert werden)
Warum differenzierst du zwischen den beiden Typen? Gibt es dabei einen Vorteil? Was hälst du davon für beide Typen, Exceptions zu verwenden? Wie erstellst du die Fehlermeldung und wie fängst du sie ab (Setzt du die Fehlerbeschreibung gleich in der Funktion oder erst im catch Block? Verwendest du Error Codes?)?

Zitat:
Nicht aufgefangene Fehler kannst du Hierarchisch nach "oben" weiterreichen, um
sie zu fangen.
Meinst du einen Stack zu erstellen?

Ich hatte heute etwas Zeit mich etwas mit dem PHP 5 Error Handler zu beschäftigen. Das Ergebnis gefällt mir noch nicht ganz. Es gibt auch noch einen Fehler bei der Ermittlung der Zeile und des Stacks.

PHP-Code:
<?php

error_reporting
(E_ALL);

class 
_exceptionHandler
{
    public function 
__construct()
    {
        if (isset(
$GLOBALS['errorHandler']))
        {
            throw new 
Exception('The error handler cannot be set up twice.');
        }

        if (
get_class() === get_class(&$this))
        {
            throw new 
Exception('Class ' get_class() . ' cannot be called directly.');
        }

        if (!
is_callable(array(&$this'callErrorHandler')))
        {
            throw new 
Exception('Class ' get_class() . ' does not contain a callable function being named "errorHandler".');
        }

        
set_error_handler(array(&$this'callErrorHandler'));
        
$GLOBALS['errorHandler'] = array (&$this'callErrorHandler');
    }

    public function 
callErrorHandler($errorCode$errorMessage)
    {
        
$backtrace debug_backtrace();
        unset (
$backtrace[0]);

        if (isset (
$backtrace[2]['class']) && ($backtrace[2]['class'] === 'Error'))
        {
            unset (
$backtrace[1]);
            unset (
$backtrace[2]);
        }

        
$trace array_reverse($backtrace);

        
$this->errorHandler($errorCode$errorMessage$trace);
    }

    public function 
__destruct()
    {
        if (isset(
$GLOBALS['errorHandler']))
        {
            
restore_error_handler();
            unset (
$GLOBALS['errorHandler']);
        }
    }
}

class 
Error
{
    public function 
__construct($errorMessage$errorCode 0)
    {
        if (isset (
$GLOBALS['errorHandler']) && is_callable ($GLOBALS['errorHandler']))
        {
            
call_user_func($GLOBALS['errorHandler'], $errorCode$errorMessage);
        }
        else
        {
            throw new 
Exception($errorMessage$errorCode);
        }
    }
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

class exceptionHandler extends _exceptionHandler
{
    private 
$stack = array();

    protected function 
errorHandler ($errorCode$errorMessage, array $trace)
    {
        echo 
$errorCode ': ' $errorMessage;
        echo 
"\r\n";
        
print_r($trace);
    }
}

//////////////////////////////////////////////////////////////////////////
// Exception handler ist deactivated -->> catch the exception manually
//////////////////////////////////////////////////////////////////////////

try
{
    new 
Error('errmsg');
}
catch (
Exception $e)
{
    
//Todo: Zeile modifizieren
    //Todo: Trace nicht korrekt

    
echo $e->getLine() . ': ' $e->getMessage();
    echo 
"\r\n";
    echo 
$e->getTraceAsString();
}

echo 
"\r\n";
echo 
"\r\n";

//////////////////////////////////
// Enable the exception handler
//////////////////////////////////

new exceptionHandler();

/////////////////////
// Cause a warning
/////////////////////

function test()
{
    if (
$causeWarning)
    {

    }
}

test();

echo 
"\r\n";
echo 
"\r\n";

////////////////////
// Throw an error
////////////////////

function test2()
{
    new 
Error(1'errmsg');
}

test2();

?>
Teil 1 bestehend aus den Klassen "_exceptionHandler" und "Error" ist in einer Datei abgespeichert, welche von allen Projekten inkludiert wird. Teil 2 besteht aus der Klasse "exceptionHandler", welche die Fehlermeldungen bearbeitet und für jedes Projekt individuell geschrieben wird.

Der Fehler ist in Zeile 96 - 98: Die Zeilen werden falsch angegeben, weil eine neue Instanz von "Exception" in Zeile 64 erstellt wird. Eine Möglichkeit das zu umgehen wäre auf die private Variablen von "Exception" zuzugreifen und die Werte anzupassen. Mittels debug_backtrace() kann man die korrekten Angaben herausfinden. Allerdings weiß ich noch nicht, wie man die privaten Variablen editiert. Eine andere Möglichkeit, vielleicht auch die beste, wäre, die "Exception"-Klasse neuzuschreiben und gleich die Funktion "callErrorHandler" aus Zeile 28 zu integrieren.

Vielen Dank im Voraus für eure Hilfe!

Gruß
Tim
__________________
Betriebssystem: Ubuntu 7.10, Kernel v2.6.24-8-generic
Webserver: LightTPD v1.4.13, PHP v5.2.4 + FastCGI + MySQLi v5.0.51a
qwertzu ist offline  
Alt 10.08.2007, 22:38  
Neuer Benutzer
 
Registriert seit: 10.08.2007
Beiträge: 12
qwertzu
Standard

Ich habe jetzt nocheinmal nachgedacht: Vielleicht sollte man set_error_handler() eine andere Funktion zuweisen, als dem Exception Handler, weil man dann dadurch gezielt auf alle E_* Meldungen reagieren könnte. Was haltet ihr davon?

Gruß
Tim
__________________
Betriebssystem: Ubuntu 7.10, Kernel v2.6.24-8-generic
Webserver: LightTPD v1.4.13, PHP v5.2.4 + FastCGI + MySQLi v5.0.51a
qwertzu ist offline  
Alt 11.08.2007, 00:33  
Erfahrener Benutzer
 
Benutzerbild von phpdummi
 
Registriert seit: 06.06.2008
Beiträge: 1.631
PHP-Kenntnisse:
Anfänger
phpdummi ist zur Zeit noch ein unbeschriebenes Blatt
Standard

Hallo,

ich halte viel von einem Logger, der alles Protokolliert. Dazu noch Exceptions, die bei Fehlern entsprechende Meldungen ausgeben.
Wozu "gezielt auf E_* Meldungen reagieren"? Es liegt am Programmierer ordentlich mit Fehlern umzugehen bzw. an kritischen stellen im Code ausführlich mit IF Konstrukten zu arbeiten.
Worin liegt das Problem, z.B. auf Verbindungsfehler mit der Datenbank zu reagieren?
Code:
VERSUCHE

    WENN
        Verbindung <>
    DANN
        werfe Einwand: "Datenbankverbindung nicht möglich!"
    WENN ENDE

VERSUCHE ENDE

FANGE EINWÄNDE

    Einwände System
        ....
    Einwände Daten
        ....

FANGE EINWÄNDE ENDE
__________________
"Nobody is as smart as everybody" - Kevin Kelly
— The best things in life aren't things
phpdummi ist offline  
Alt 12.08.2007, 14:51  
Erfahrener Benutzer
 
Registriert seit: 21.05.2008
Beiträge: 9.937
Zergling-new wird schon bald berühmt werden
Standard

Zitat:
Zitat von qwertzu
Zitat:
Wo heißt in dem Fall in der Abstraktionsstufe deiner Wahl. Bedarfsweise innerhalb der Klasse oder aber ganz "außen".
Das verstehe ich nicht genau.
Sagen wir die Methode kopieren() der Klasse DateiListe kopiert mehrere Dateien. Beim Kopieren treten Rechteprobleme mit dem Dateisystem auf, die verwendete Systemfunktion copy() meldet einen Fehler.
Jetzt kannst du entweder ein try-catch um die copy() Operation legen und versuchen das Problem noch in der kopieren()-Methode zu lösen. Zum Beispiel durch chmod() Aufruf und den erneuten Kopierversuch.
PHP-Code:
<?php
function kopieren()
{
  try {
    
// kopiere
  
} catch (Exception $e) {
    
// stelle Fehler fest, rufe chmod() auf und sorge dafür, dass das
    // kopieren ab der Stelle nocheinmal weiterversucht wird
  
}
}
?>
Du kannst das Problem aber auch außerhalb der Klasse, nämlich dort wo die kopieren() Methode angestossen wurde, lösen.
PHP-Code:
<?php
function kopieren()
{
  
// kopiere
}
// Anwendungscode
try {
  
$dateiliste->kopieren();
} catch (
Exception $e) {
  
// schicke den Benutzer zur Seite, in der er die Dateiliste bearbeiten kann
}
?>
Oder eben ganz aussen, wo deine Hauptapplikation läuft.
PHP-Code:
<?php
try {
  
// komplette Anwendung
} catch (Exception $e) {
  die(
$e->getMessage());
}
?>
Das meinte ich mit Abstraktionsstufe. Ziemlich flexibel wie ich meine, im Gegensatz zum Error-Handler.
Zergling-new ist offline  
 


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

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
php error handling, php5 error handling, error handling php, lighttpd trace php, http://www.php.de/php-tipps-2007/44555-errorhandling-mit-php-5-a.html, errorhandling php, php5 trace, php eigene exception klasse, php error handling exception klasse, trigger_error fangen, errorhandler php, php exception handler trace schön, r error handling, php methodenaufruf herausfinden an welcher stelle, php error handling class, \error 6 in php5\, errorhandler exceptionhandler log schreiben, php eigene exception-klasse php5, php5 exception handling, php error trace

Alle Zeitangaben in WEZ +2. Es ist jetzt 15:48 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.