Come posso rilevare un errore irreversibile di PHP (`E_ERROR`)?


557

Posso usare set_error_handler()per catturare la maggior parte degli errori PHP, ma non funziona per E_ERRORerrori fatali ( ), come chiamare una funzione che non esiste. C'è un altro modo per rilevare questi errori?

Sto cercando di chiamare mail()tutti gli errori e sto eseguendo PHP 5.2.3.


Ho scritto domande e risposte in stile wiki con una soluzione completa per rilevare tutti gli errori in PHP; che può essere visualizzato / raccolto / rubato / criticato qui su Stack Overflow . La soluzione include cinque metodi che racchiudono tutti gli errori che PHP può generare che alla fine passeranno detti errori a un oggetto tipizzato "ErrorHandler".
DigitalJedi805,



Risposte:


635

Registra errori fatali usando il register_shutdown_function, che richiede PHP 5.2+:

register_shutdown_function( "fatal_handler" );

function fatal_handler() {
    $errfile = "unknown file";
    $errstr  = "shutdown";
    $errno   = E_CORE_ERROR;
    $errline = 0;

    $error = error_get_last();

    if($error !== NULL) {
        $errno   = $error["type"];
        $errfile = $error["file"];
        $errline = $error["line"];
        $errstr  = $error["message"];

        error_mail(format_error( $errno, $errstr, $errfile, $errline));
    }
}

Dovrai definire le funzioni error_maile format_error. Per esempio:

function format_error( $errno, $errstr, $errfile, $errline ) {
    $trace = print_r( debug_backtrace( false ), true );

    $content = "
    <table>
        <thead><th>Item</th><th>Description</th></thead>
        <tbody>
            <tr>
                <th>Error</th>
                <td><pre>$errstr</pre></td>
            </tr>
            <tr>
                <th>Errno</th>
                <td><pre>$errno</pre></td>
            </tr>
            <tr>
                <th>File</th>
                <td>$errfile</td>
            </tr>
            <tr>
                <th>Line</th>
                <td>$errline</td>
            </tr>
            <tr>
                <th>Trace</th>
                <td><pre>$trace</pre></td>
            </tr>
        </tbody>
    </table>";
    return $content;
}

Utilizzare Swift Mailer per scrivere la error_mailfunzione.

Guarda anche:


113
+1 Questa è la risposta corretta effettiva . Non so perché le persone si stiano bloccando su "non puoi recuperare da errori fatali" - la domanda non ha detto nulla sul recupero.
David Harkness,

21
Grazie, bravo. Il recupero da errori fatali (limiti di memoria, ad esempio) non è qualcosa che vorrei provare a fare, ma rendere questi errori rilevabili (senza che il cliente presenti un ticket di supporto) fa la differenza.
Ilija,

2
Usando la posta base:mail("myname@myemail.com", "My Site: FATAL ERROR", "Details: " . $errno . ' ' . $errstr . ' ' . $errfile . ' ' . $errline);
Eric Muyser il

4
@ScottNicol Slava V è corretto, perché la funzione di arresto viene chiamata ogni volta che lo script termina l'esecuzione. Con il modo in cui il codice è stato scritto ora, verrà inviata un'e-mail al caricamento di OGNI pagina.
Nate,

2
Nota: questa non è una risposta corretta al 100%. Qualsiasi luogo che utilizza un simbolo @ per ignorare gli errori imposterà comunque l'ultimo errore (in modo da poter gestire gli errori). Quindi lo script termina senza problemi ma la funzione register_shutdown_ pensa ancora che si sia verificato un errore. Solo da quando PHP 7 hanno avuto una funzione error_clear_last ().
Rahly,

150

Ho appena trovato questa soluzione (PHP 5.2.0+):

function shutDownFunction() {
    $error = error_get_last();
     // Fatal error, E_ERROR === 1
    if ($error['type'] === E_ERROR) {
         // Do your stuff
    }
}
register_shutdown_function('shutDownFunction');

Diversi tipi di errore sono definiti in Costanti predefinite .


25
Questa soluzione fa molto di più per me rispetto alla risposta più votata. La risposta più votata ti invierà un'email ogni volta che lo script viene eseguito, anche se non si verificano errori. Questo corre rigorosamente su un errore fatale.
kmoney12

@periklis, se l'ultimo errore fosse già stato gestito, error_get_last lo avrebbe comunque restituito, no?
Pacerier,

@Pacerier Non sono sicuro di cosa intendi con "gestito", poiché gli errori non sono eccezioni, ma suppongo che la risposta sia "sì"
periklis,

3
@Pacerier Capisco, questa è una domanda interessante. If an error handler (see set_error_handler ) successfully handles an error then that error will not be reported by this function.
Dai

1
Forse questo è ovvio, la chiamata register_shutdown_function()deve essere precedente a qualsiasi errore fatale. use_1T_memory(); /* memory exhausted error here! */ register_shutdown_function('shutDownFunction');non funzionerà come previsto.
Nobu,

117

PHP non fornisce mezzi convenzionali per la cattura e il recupero da errori fatali. Questo perché l'elaborazione non dovrebbe in genere essere recuperata dopo un errore fatale. La stringa che corrisponde a un buffer di output (come suggerito dal post originale la tecnica descritta su PHP.net) è decisamente sconsigliata. È semplicemente inaffidabile.

Anche chiamare la funzione mail () da un metodo di gestione degli errori si rivela problematico. Se avessi molti errori, il tuo server di posta verrebbe caricato con lavoro e potresti ritrovarti con una posta in arrivo nodosa. Per evitare ciò, potresti prendere in considerazione l'esecuzione di un cron per scansionare periodicamente i log degli errori e inviare le notifiche di conseguenza. Potresti anche esaminare il software di monitoraggio del sistema, come Nagios .


Per parlare con un po 'della registrazione di una funzione di spegnimento:

È vero che puoi registrare una funzione di spegnimento, e questa è una buona risposta.

Il punto qui è che in genere non dovremmo provare a recuperare da errori fatali, soprattutto non usando un'espressione regolare sul buffer di output. Stavo rispondendo alla risposta accettata , che si collegava a un suggerimento su php.net che da allora è stato modificato o rimosso.

Quel suggerimento era di usare una regex contro il buffer di output durante la gestione delle eccezioni e, nel caso di un errore fatale (rilevato dalla corrispondenza con qualsiasi testo di errore configurato che ci si potrebbe aspettare), provare a fare una sorta di recupero o elaborazione continua. Non sarebbe una pratica raccomandata (credo sia per questo che non riesco a trovare anche il suggerimento originale. Lo sto trascurando o la community di php lo ha abbattuto).

Vale la pena notare che le versioni più recenti di PHP (intorno alla 5.1) sembrano chiamare la funzione di arresto in precedenza, prima che venga invocato il callback del buffer di output. Nella versione 5 e precedenti, quell'ordine era il contrario (il callback del buffering dell'output era seguito dalla funzione di spegnimento). Inoltre, poiché circa 5.0.5 (che è molto precedente alla versione 5.2.3 dell'interrogatore), gli oggetti vengono scaricati ben prima che venga chiamata una funzione di arresto registrata, quindi non sarà possibile fare affidamento sugli oggetti in memoria da fare molto di tutto.

Quindi la registrazione di una funzione di spegnimento va bene, ma il tipo di attività che dovrebbero essere eseguite da una funzione di spegnimento è probabilmente limitato a una manciata di procedure di spegnimento delicato.

La chiave da asporto qui sono solo alcune parole di saggezza per chiunque si imbatta in questa domanda e vede i consigli nella risposta inizialmente accettata. Non regex il buffer di output.


25
Pfff, ricordo quelle più di 650.000 e-mail che ho ricevuto la mattina seguente. Da allora il mio ErrorHandler è limitato a 100 e-mail per server web.
Bob Fanger,

14
Non è vero. È possibile acquisire errori irreversibili con register_shutdown_function.
hipertracker,

56
Esistono casi d'uso per voler rilevare errori fatali. Le suite di test, ad esempio, non dovrebbero limitarsi a fermarsi quando si fallisce, dovrebbero riportare l'errore fatale e passare al test successivo. PHP rende semplicemente troppe cose errori "fatali".
Chad,

24
Sì, dire che "non dovrebbero essere catturati" è molto miope. In un sistema di produzione, è necessario sapere quando qualcosa non riesce (istituito messaggi di posta elettronica o accedere le cose in un database - gestione degli errori php di default non è molto sofisticato).
BT,

8
Voglio fare un breve commento su ciò che tutti voi dite su "Gli errori devono essere colti, in modo che possiamo risolverli" ... Ini direttive ini log_errors ed error_log.
Kelly Elton,

37

Bene, sembra possibile rilevare errori fatali in qualche altro modo :)

ob_start('fatal_error_handler');

function fatal_error_handler($buffer){
    $error = error_get_last();
    if($error['type'] == 1){
        // Type, message, file, line
        $newBuffer='<html><header><title>Fatal Error </title></header>
                      <style>
                    .error_content{
                        background: ghostwhite;
                        vertical-align: middle;
                        margin:0 auto;
                        padding: 10px;
                        width: 50%;
                     }
                     .error_content label{color: red;font-family: Georgia;font-size: 16pt;font-style: italic;}
                     .error_content ul li{ background: none repeat scroll 0 0 FloralWhite;
                                border: 1px solid AliceBlue;
                                display: block;
                                font-family: monospace;
                                padding: 2%;
                                text-align: left;
                      }
                      </style>
                      <body style="text-align: center;">
                        <div class="error_content">
                             <label >Fatal Error </label>
                             <ul>
                               <li><b>Line</b> ' . $error['line'] . '</li>
                               <li><b>Message</b> ' . $error['message'] . '</li>
                               <li><b>File</b> ' . $error['file'] . '</li>
                             </ul>

                             <a href="javascript:history.back()"> Back </a>
                        </div>
                      </body></html>';

        return $newBuffer;
    }
    return $buffer;
}

3
Darei questi 10 voti se potessi. Funziona perfettamente per me su quegli strani errori che a volte si verificano quando una pagina bombarda e nulla viene registrato. Non userei nel codice di produzione live, ma è bello aggiungere a una pagina quando è necessaria una risposta rapida a ciò che non funziona. Grazie!
Nottambulo

Una delle migliori soluzioni che ho trovato su Internet. Funziona come il fascino.
Rimbalzo

In quale modo? Una spiegazione sarebbe in ordine, soprattutto se è una delle migliori soluzioni su Internet (potrebbe diventare ancora migliore).
Peter Mortensen,

Ad esempio, è necessario tutto il contenuto CSS? Non potrebbe essere ridotto all'essenziale? Rispondi modificando la risposta, non qui nei commenti (a seconda dei casi).
Peter Mortensen,

@PeterMortensen Non pretendo il meglio. Anche la mia soluzione personale al problema, ci sono altre opzioni migliori e molto professionali. Come suggerito da qualcuno, non è adatto alla produzione. Css è lì perché ho appena incollato il mio codice personale
sakhunzai il

36

Errori fatali o errori irreversibili recuperabili ora generano istanze Errorin PHP 7 o versioni successive . Come ogni altra eccezione, gli Erroroggetti possono essere catturati usando un try/catchblocco.

Esempio:

<?php
$variable = 'not an object';

try {
    $variable->method(); // Throws an Error object in PHP 7 or higger.
} catch (Error $e) {
    // Handle error
    echo $e->getMessage(); // Call to a member function method() on string
}

https://3v4l.org/67vbk

Oppure puoi usare l' Throwableinterfaccia per catturare tutte le eccezioni.

Esempio:

<?php
    try {
        undefinedFunctionCall();
    } catch (Throwable $e) {
        // Handle error
        echo $e->getMessage(); // Call to undefined function undefinedFunctionCall()
    }

https://3v4l.org/Br0MG

Per maggiori informazioni: http://php.net/manual/en/language.errors.php7.php


2
Qualche idea su come usare questo per rilevare un errore come Fatal error: Trait 'FailedTrait' not found inquando si usa ReflectionClass?
TCB13

1
@ TCB13 prova a racchiudere il contenuto interno di prova in un file e include "filename.php"invece nel tryblocco, quindi Throwablecattura il blocco almeno per cui funziona ParseError.
Niloct

24

Ho sviluppato un modo per rilevare tutti i tipi di errore in PHP (quasi tutti)! Non sono sicuro di E_CORE_ERROR (penso che non funzionerà solo per quell'errore)! Ma, per altri errori fatali (E_ERROR, E_PARSE, E_COMPILE ...) funziona bene usando solo una funzione di gestione degli errori! Ecco la mia soluzione:

Inserisci questo codice nel tuo file principale (index.php):

<?php
    define('E_FATAL',  E_ERROR | E_USER_ERROR | E_PARSE | E_CORE_ERROR |
            E_COMPILE_ERROR | E_RECOVERABLE_ERROR);

    define('ENV', 'dev');

    // Custom error handling vars
    define('DISPLAY_ERRORS', TRUE);
    define('ERROR_REPORTING', E_ALL | E_STRICT);
    define('LOG_ERRORS', TRUE);

    register_shutdown_function('shut');

    set_error_handler('handler');

    // Function to catch no user error handler function errors...
    function shut(){

        $error = error_get_last();

        if($error && ($error['type'] & E_FATAL)){
            handler($error['type'], $error['message'], $error['file'], $error['line']);
        }

    }

    function handler( $errno, $errstr, $errfile, $errline ) {

        switch ($errno){

            case E_ERROR: // 1 //
                $typestr = 'E_ERROR'; break;
            case E_WARNING: // 2 //
                $typestr = 'E_WARNING'; break;
            case E_PARSE: // 4 //
                $typestr = 'E_PARSE'; break;
            case E_NOTICE: // 8 //
                $typestr = 'E_NOTICE'; break;
            case E_CORE_ERROR: // 16 //
                $typestr = 'E_CORE_ERROR'; break;
            case E_CORE_WARNING: // 32 //
                $typestr = 'E_CORE_WARNING'; break;
            case E_COMPILE_ERROR: // 64 //
                $typestr = 'E_COMPILE_ERROR'; break;
            case E_CORE_WARNING: // 128 //
                $typestr = 'E_COMPILE_WARNING'; break;
            case E_USER_ERROR: // 256 //
                $typestr = 'E_USER_ERROR'; break;
            case E_USER_WARNING: // 512 //
                $typestr = 'E_USER_WARNING'; break;
            case E_USER_NOTICE: // 1024 //
                $typestr = 'E_USER_NOTICE'; break;
            case E_STRICT: // 2048 //
                $typestr = 'E_STRICT'; break;
            case E_RECOVERABLE_ERROR: // 4096 //
                $typestr = 'E_RECOVERABLE_ERROR'; break;
            case E_DEPRECATED: // 8192 //
                $typestr = 'E_DEPRECATED'; break;
            case E_USER_DEPRECATED: // 16384 //
                $typestr = 'E_USER_DEPRECATED'; break;
        }

        $message =
            '<b>' . $typestr .
            ': </b>' . $errstr .
            ' in <b>' . $errfile .
            '</b> on line <b>' . $errline .
            '</b><br/>';

        if(($errno & E_FATAL) && ENV === 'production'){

            header('Location: 500.html');
            header('Status: 500 Internal Server Error');

        }

        if(!($errno & ERROR_REPORTING))
            return;

        if(DISPLAY_ERRORS)
            printf('%s', $message);

        //Logging error on php file error log...
        if(LOG_ERRORS)
            error_log(strip_tags($message), 0);
    }

    ob_start();

    @include 'content.php';

    ob_end_flush();
?>

2
Cosa fa la riga @include 'content.php'?
Marco

22

Non è possibile rilevare / gestire errori fatali, ma è possibile registrarli / segnalarli. Per il debug rapido ho modificato una risposta a questo semplice codice

function __fatalHandler()
{
    $error = error_get_last();

    // Check if it's a core/fatal error, otherwise it's a normal shutdown
    if ($error !== NULL && in_array($error['type'],
        array(E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING,
              E_COMPILE_ERROR, E_COMPILE_WARNING,E_RECOVERABLE_ERROR))) {

        echo "<pre>fatal error:\n";
        print_r($error);
        echo "</pre>";
        die;
    }
}

register_shutdown_function('__fatalHandler');

ma dove andrebbe questo codice?
TKoL

@TKoL prima riga. Fondamentalmente inserisci il file del tuo script / programma, quindi viene eseguito per primo, se ciò non è possibile mettilo in un file comune
zainengineer

17

Non è possibile generare un'eccezione all'interno di una funzione di arresto registrata come quella:

<?php
    function shutdown() {
        if (($error = error_get_last())) {
           ob_clean();
           throw new Exception("fatal error");
        }
    }

    try {
        $x = null;
        $x->method()
    } catch(Exception $e) {
        # This won't work
    }
?>

Ma puoi acquisire e reindirizzare la richiesta a un'altra pagina.

<?php
    function shutdown() {
        if (($error = error_get_last())) {
           ob_clean();
           # Report the event, send email, etc.
           header("Location: http://localhost/error-capture");
           # From /error-capture. You can use another
           # redirect, to e.g. the home page
        }
    }
    register_shutdown_function('shutdown');

    $x = null;
    $x->method()
?>

11

Se stai usando PHP> = 5.1.0 Fai qualcosa di simile con la classe ErrorException:

<?php
    // Define an error handler
    function exception_error_handler($errno, $errstr, $errfile, $errline ) {
        throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
    }

    // Set your error handler
    set_error_handler("exception_error_handler");

    /* Trigger exception */
    try
    {
        // Try to do something like finding the end of the internet
    }
    catch(ErrorException $e)
    {
        // Anything you want to do with $e
    }
?>

9

Bella soluzione trovata in Zend Framework 2:

/**
 * ErrorHandler that can be used to catch internal PHP errors
 * and convert to an ErrorException instance.
 */
abstract class ErrorHandler
{
    /**
     * Active stack
     *
     * @var array
     */
    protected static $stack = array();

    /**
     * Check if this error handler is active
     *
     * @return bool
     */
    public static function started()
    {
        return (bool) static::getNestedLevel();
    }

    /**
     * Get the current nested level
     *
     * @return int
     */
    public static function getNestedLevel()
    {
        return count(static::$stack);
    }

    /**
     * Starting the error handler
     *
     * @param int $errorLevel
     */
    public static function start($errorLevel = \E_WARNING)
    {
        if (!static::$stack) {
            set_error_handler(array(get_called_class(), 'addError'), $errorLevel);
        }

        static::$stack[] = null;
    }

    /**
     * Stopping the error handler
     *
     * @param  bool $throw Throw the ErrorException if any
     * @return null|ErrorException
     * @throws ErrorException If an error has been catched and $throw is true
     */
    public static function stop($throw = false)
    {
        $errorException = null;

        if (static::$stack) {
            $errorException = array_pop(static::$stack);

            if (!static::$stack) {
                restore_error_handler();
            }

            if ($errorException && $throw) {
                throw $errorException;
            }
        }

        return $errorException;
    }

    /**
     * Stop all active handler
     *
     * @return void
     */
    public static function clean()
    {
        if (static::$stack) {
            restore_error_handler();
        }

        static::$stack = array();
    }

    /**
     * Add an error to the stack
     *
     * @param int    $errno
     * @param string $errstr
     * @param string $errfile
     * @param int    $errline
     * @return void
     */
    public static function addError($errno, $errstr = '', $errfile = '', $errline = 0)
    {
        $stack = & static::$stack[count(static::$stack) - 1];
        $stack = new ErrorException($errstr, 0, $errno, $errfile, $errline, $stack);
    }
}

Questa classe ti consente di avviare lo specifico a ErrorHandlervolte se ne hai bisogno. E poi puoi anche fermare il Gestore.

Usa questa classe, ad esempio in questo modo:

ErrorHandler::start(E_WARNING);
$return = call_function_raises_E_WARNING();

if ($innerException = ErrorHandler::stop()) {
    throw new Exception('Special Exception Text', 0, $innerException);
}

// or
ErrorHandler::stop(true); // directly throws an Exception;

Link al codice completo della classe:
https://github.com/zendframework/zf2/blob/master/library/Zend/Stdlib/ErrorHandler.php


Una soluzione forse migliore è quella di Monolog :

Link al codice completo della classe:
https://github.com/Seldaek/monolog/blob/master/src/Monolog/ErrorHandler.php

Può anche gestire FATAL_ERRORS utilizzando la register_shutdown_functionfunzione. Secondo questa classe un FATAL_ERROR è uno dei seguenti array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR).

class ErrorHandler
{
    // [...]

    public function registerExceptionHandler($level = null, $callPrevious = true)
    {
        $prev = set_exception_handler(array($this, 'handleException'));
        $this->uncaughtExceptionLevel = $level;
        if ($callPrevious && $prev) {
            $this->previousExceptionHandler = $prev;
        }
    }

    public function registerErrorHandler(array $levelMap = array(), $callPrevious = true, $errorTypes = -1)
    {
        $prev = set_error_handler(array($this, 'handleError'), $errorTypes);
        $this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap);
        if ($callPrevious) {
            $this->previousErrorHandler = $prev ?: true;
        }
    }

    public function registerFatalHandler($level = null, $reservedMemorySize = 20)
    {
        register_shutdown_function(array($this, 'handleFatalError'));

        $this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize);
        $this->fatalLevel = $level;
    }

    // [...]
}

9

Devo gestire errori fatali per la produzione per mostrare invece un output HTML non disponibile 503 in stile statico . Questo è sicuramente un approccio ragionevole per "rilevare errori fatali". Questo è quello che ho fatto:

Ho una funzione personalizzata di gestione degli errori "error_handler" che visualizzerà la mia pagina HTML "503 servizio non disponibile" su qualsiasi E_ERROR, E_USER_ERROR, ecc. Questo verrà ora chiamato sulla funzione di spegnimento, rilevando il mio errore fatale,

function fatal_error_handler() {

    if (@is_array($e = @error_get_last())) {
        $code = isset($e['type']) ? $e['type'] : 0;
        $msg = isset($e['message']) ? $e['message'] : '';
        $file = isset($e['file']) ? $e['file'] : '';
        $line = isset($e['line']) ? $e['line'] : '';
        if ($code>0)
            error_handler($code, $msg, $file, $line);
    }
}
set_error_handler("error_handler");
register_shutdown_function('fatal_error_handler');

nella mia funzione personalizzata error_handler, se l'errore è E_ERROR, E_USER_ERROR, ecc. Chiamo anche @ob_end_clean();per svuotare il buffer, rimuovendo così il messaggio di "errore fatale" di PHP.

Prendi nota delle rigorose @funzioni di controllo e silenziamento di isset () poiché non vogliamo che i nostri script error_handler generino errori.

In accordo con Keparo, la cattura di errori fatali vanifica lo scopo di "errore FATAL", quindi non è realmente previsto che tu debba effettuare ulteriori elaborazioni. Non eseguire alcuna funzione mail () in questo processo di arresto poiché eseguirà sicuramente il backup del server di posta o della posta in arrivo. Piuttosto registra queste occorrenze per archiviare e pianificare un processo cron per trovare questi file error.log e inviarli agli amministratori.


7

PHP ha errori fatali rilevabili. Sono definiti come E_RECOVERABLE_ERROR. Il manuale di PHP descrive un E_RECOVERABLE_ERROR come:

Errore irreversibile irreversibile. Indica che si è verificato un errore probabilmente pericoloso, ma non ha lasciato il motore in uno stato instabile. Se l'errore non viene rilevato da un handle definito dall'utente (vedere anche set_error_handler () ), l'applicazione si interrompe in quanto E_ERROR.

Puoi "catturare" questi errori "fatali" usando set_error_handler () e controllando E_RECOVERABLE_ERROR. Trovo utile generare un'eccezione quando viene rilevato questo errore, quindi è possibile utilizzare try / catch.

Questa domanda e risposta fornisce un utile esempio: come posso rilevare un "errore irreversibile irreversibile" nel suggerimento sul tipo di PHP?

Gli errori E_ERROR, tuttavia, possono essere gestiti, ma non recuperati poiché il motore è in uno stato instabile.


6

Ecco un bel trucco per ottenere l'attuale metodo error_handler =)

<?php
    register_shutdown_function('__fatalHandler');

    function __fatalHandler()
    {
        $error = error_get_last();

        // Check if it's a core/fatal error. Otherwise, it's a normal shutdown
        if($error !== NULL && $error['type'] === E_ERROR) {

            // It is a bit hackish, but the set_exception_handler
            // will return the old handler
            function fakeHandler() { }

            $handler = set_exception_handler('fakeHandler');
            restore_exception_handler();
            if($handler !== null) {
                call_user_func(
                    $handler,
                    new ErrorException(
                        $error['message'],
                        $error['type'],
                        0,
                        $error['file'],
                        $error['line']));
            }
            exit;
        }
    }
?>

Voglio anche notare che se chiami

<?php
    ini_set('display_errors', false);
?>

PHP interrompe la visualizzazione dell'errore. In caso contrario, il testo dell'errore verrà inviato al client prima del gestore degli errori.


1
È stato valutato a causa della riga ini_set ('display_errors', false);
Sahib Khan,

Se per qualche ragione questo bit è attivo mostrerà comunque errori php anche se lo gestisci in modo diverso
Sahib Khan

5

Poiché la maggior parte delle risposte qui sono inutilmente prolisse, ecco la mia versione non brutta della risposta più votata:

function errorHandler($errno, $errstr, $errfile = '', $errline = 0, $errcontext = array()) {
    //Do stuff: mail, log, etc
}

function fatalHandler() {
    $error = error_get_last();
    if($error) errorHandler($error["type"], $error["message"], $error["file"], $error["line"]);
}

set_error_handler("errorHandler")
register_shutdown_function("fatalHandler");

4

Non proprio. Gli errori fatali si chiamano così, perché sono fatali. Non puoi riprenderti da loro.


12
la cattura e il recupero sono due cose molto diverse.
Simon Forsberg,

3

Ho sviluppato questa funzione per rendere possibile il "sandbox" del codice che potrebbe causare un errore fatale. Poiché le eccezioni generate dalla chiusura register_shutdown_functionnon vengono emesse dallo stack di chiamate di errore pre-fatale, sono costretto a uscire dopo questa funzione per fornire un modo uniforme di utilizzarlo.

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();
}

3

Ci sono alcune circostanze in cui anche gli errori fatali dovrebbero essere colti (potrebbe essere necessario fare un po 'di pulizia prima di uscire con grazia e non solo morire ..).

Ho implementato un hook pre_system nelle mie applicazioni CodeIgniter in modo da poter ottenere i miei errori fatali tramite e-mail e questo mi ha aiutato a trovare bug che non sono stati segnalati (o sono stati segnalati dopo che sono stati corretti, come già sapevo su di loro :)).

Sendemail verifica se l'errore è già stato segnalato in modo che non ti invii più volte spam con errori noti.

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();
    }
}

Che cos'è "Sendemail" ? Intendi Sendmail (rispondi modificando la tua risposta , non qui nei commenti)?
Peter Mortensen,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.