602 Stimmen

Wie fange ich einen fatalen PHP-Fehler (`E_ERROR`) ab?

Ich kann set_error_handler() um die meisten PHP-Fehler abzufangen, aber es funktioniert nicht bei fatalen ( E_ERROR ) Fehler, wie z.B. der Aufruf einer Funktion, die nicht existiert. Gibt es eine andere Möglichkeit, diese Fehler abzufangen?

Ich versuche zu telefonieren mail() für alle Fehler und ich verwende PHP 5.2.3.

3voto

Kendall Hopkins Punkte 41041

Ich habe diese Funktion entwickelt, um Code, der einen schwerwiegenden Fehler verursachen könnte, in einer "Sandbox" zu speichern. Da Ausnahmen, die von der Schließung register_shutdown_function nicht aus dem Stapel der vorzeitigen Fehleraufrufe ausgegeben werden, bin ich gezwungen, nach dieser Funktion zu beenden, um eine einheitliche Art und Weise der Verwendung bereitzustellen.

function superTryCatchFinallyAndExit( Closure $try, Closure $catch = NULL, Closure $finally )
{
    $finished = FALSE;
    register_shutdown_function( function() use ( &$finished, $catch, $finally ) {
        if( ! $finished ) {
            $finished = TRUE;
            print "EXPLODE!".PHP_EOL;
            if( $catch ) {
                superTryCatchFinallyAndExit( function() use ( $catch ) {
                    $catch( new Exception( "Fatal Error!!!" ) );
                }, NULL, $finally );                
            } else {
                $finally();                
            }
        }
    } );
    try {
        $try();
    } catch( Exception $e ) {
        if( $catch ) {
            try {
                $catch( $e );
            } catch( Exception $e ) {}
        }
    }
    $finished = TRUE;
    $finally();
    exit();
}

3voto

tix3 Punkte 1132

Es gibt bestimmte Umstände, unter denen sogar tödliche Fehler abgefangen werden sollten (Sie müssen möglicherweise einige Aufräumarbeiten durchführen, bevor Sie ordnungsgemäß beendet werden und nicht einfach sterben ).

Ich habe einen pre_system-Haken in meine CodeIgniter Anwendungen, so dass ich meine schwerwiegenden Fehler per E-Mail erhalten kann, und das hat mir geholfen, Fehler zu finden, die nicht gemeldet wurden (oder gemeldet wurden, nachdem sie behoben waren, da ich sie bereits kannte :)).

Sendemail prüft, ob der Fehler bereits gemeldet wurde, damit Sie nicht mehrfach mit bekannten Fehlern zugemüllt werden.

class PHPFatalError {

    public function setHandler() {
        register_shutdown_function('handleShutdown');
    }
}

function handleShutdown() {
    if (($error = error_get_last())) {
        ob_start();
        echo "<pre>";
        var_dump($error);
        echo "</pre>";
        $message = ob_get_clean();
        sendEmail($message);
        ob_start();
        echo '{"status":"error","message":"Internal application error!"}';
        ob_flush();
        exit();
    }
}

0voto

David Spector Punkte 1194

Ab PHP 7.4.13 ist meine Erfahrung, dass alle möglichen Fehler und Ausnahmen in einem Programm mit nur zwei Callback-Funktionen abgefangen werden können:

set_error_handler("ErrorCB");
set_exception_handler("ExceptCB");

ErrorCB meldet einfach seine Argumente auf beliebige Weise und ruft Exit() auf.

ExceptCB ruft "get"-Methoden für sein Ausnahmeargument auf und führt eine gewisse Logik aus, um festzustellen, wo sich die Datei, die Zeile und die Funktion befinden (fragen Sie mich, wenn Sie Einzelheiten erfahren möchten), und meldet die Informationen auf beliebige Weise und kehrt zurück.

Die einzige Notwendigkeit für try/catch ist, wenn Sie Fehler für bestimmten Code unterdrücken müssen, wenn @ oder isset() nicht ausreichen. Die Verwendung von try/catch für eine "Hauptfunktion" ohne das Setzen von Handlern schlägt fehl, da sie nicht alle Fehler abfängt.

Wenn jemand Code findet, der einen Fehler erzeugt, den dieser Ansatz nicht abfängt, lassen Sie es mich bitte wissen, und ich werde diese Antwort bearbeiten. Ein Fehler, den dieser Ansatz nicht abfangen kann, ist ein einzelnes {-Zeichen am Ende eines PHP-Programms; dies erzeugt einen Parse-Fehler, der erfordert, dass Sie Ihr Haupt-PHP-Programm über eine Include-Datei ausführen, die die Fehlerbehandlung enthält.

Ich habe keine Notwendigkeit für register_shutdown_function() gefunden.

Beachten Sie, dass alles, was mich interessiert, das Melden von Fehlern und das anschließende Beenden des Programms ist; ich muss mich nicht von Fehlern erholen - das wäre in der Tat eine viel schwierigere Frage.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X