如何捕获PHP致命错误

别等时光非礼了梦想. 提交于 2020-02-26 08:35:55

我可以使用set_error_handler()捕获大多数PHP错误,但是对于致命的( E_ERROR )错误(例如调用不存在的函数)不起作用。 还有另一种捕获这些错误的方法吗?

我正在尝试针对所有错误调用mail() ,并且正在运行PHP 5.2.3。


#1楼

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

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

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

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

但是,可以处理E_ERROR错误,但由于引擎处于不稳定状态,因此无法从中恢复。


#2楼

我开发了一种方法来捕获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();

?>

希望对很多人有帮助! 我搜索此解决方案的时间过长,没有找到! 然后我开发了一个!


#3楼

如果您使用的是php> = 5.1.0,只需对ErrorException类执行以下操作:

<?php
//define an error handler
function exception_error_handler($errno, $errstr, $errfile, $errline ) {
    throw new ErrorException($errstr, $errno, 0, $errfile, $errline);
}
//set ur error handle
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
}

?>

#4楼

在某些情况下,即使是致命的错误也应被捕获(您可能需要进行一些清理才能优雅地退出,不要仅仅死掉..)。 我已经在我的codeigniter应用程序上实现了pre_system挂钩,以便可以通过电子邮件获取致命错误,这有助于我发现未报告的错误(或在修复后报告的错误,因为我已经知道它们了:)。 Sendemail检查是否已报告该错误,从而不会多次向您发送已知错误的垃圾邮件。

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

#5楼

获得当前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) {
        //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;
    }
}
?>

我也不会注意到如果你打电话

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

PHP停止显示错误,否则错误文本将在错误处理程序之前发送给客户端

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!