我可以使用set_error_handler()来捕获大多数PHP错误,但它不适用于致命(E_ERROR)错误,例如调用不存在的函数。是否有其他方法来捕捉这些错误?

我试图调用mail()为所有错误和运行PHP 5.2.3。


当前回答

在PHP 7或更高版本中,致命错误或可恢复的致命错误现在会抛出错误实例。像任何其他异常一样,Error对象可以使用try/catch块捕获。

例子:

<?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

或者您可以使用Throwable接口来捕获所有异常。

例子:

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

https://3v4l.org/Br0MG

欲了解更多信息:http://php.net/manual/en/language.errors.php7.php

其他回答

不是真的。之所以叫致命错误,是因为它们是致命的。你无法从中恢复过来。

我需要处理生产的致命错误,而不是显示静态样式的503服务不可用HTML输出。这无疑是“捕捉致命错误”的合理方法。这就是我所做的:

我有一个自定义错误处理函数“error_handler”,它将在任何E_ERROR, E_USER_ERROR等上显示我的“503服务不可用”HTML页面。这将被shutdown函数调用,捕捉致命错误,

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');

在我的自定义error_handler函数中,如果错误是E_ERROR, E_USER_ERROR等。我还调用@ob_end_clean();清空缓冲区,从而删除PHP的“致命错误”消息。

请注意严格的isset()检查和@ silence函数,因为我们不希望error_handler脚本生成任何错误。

在仍然同意keparo的情况下,捕获致命错误确实没有达到“致命错误”的目的,因此它实际上并不打算让您做进一步的处理。在此关闭过程中不要运行任何mail()函数,因为您肯定会备份邮件服务器或收件箱。而是将这些事件记录到文件中,并安排一个cron作业来查找这些error.log文件并将它们发送给管理员。

由于这里的大多数答案都是不必要的啰嗦,下面是我投票最多的答案的不丑陋版本:

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");

我开发了一种方法来捕获PHP中的所有错误类型(几乎所有)!我不确定E_CORE_ERROR(我认为不会仅适用于该错误)!但是,对于其他致命错误(E_ERROR, E_PARSE, E_COMPILE…),只使用一个错误处理函数就可以正常工作!这就是我的解决方案:

把下面的代码放在你的主文件(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();
?>

PHP有可捕获的致命错误。它们被定义为E_RECOVERABLE_ERROR。PHP手册将E_RECOVERABLE_ERROR描述为:

可捕捉的致命错误。它表示可能发生了危险的错误,但没有使引擎处于不稳定状态。如果用户定义的句柄没有捕捉到错误(参见set_error_handler()),应用程序将中止,因为它是一个E_ERROR。

您可以通过使用set_error_handler()并检查E_RECOVERABLE_ERROR来“捕获”这些“致命”错误。我发现当这个错误被捕获时抛出一个异常很有用,然后你可以使用try/catch。

这个问题和答案提供了一个有用的例子:如何在PHP类型提示中捕获“可捕获的致命错误”?

然而,E_ERROR错误可以处理,但不能恢复,因为引擎处于不稳定状态。