PHP:自定义错误处理程序 - 处理解析和致命错误

A.N*_*lam 54 php error-handling parse-error fatal-error

如何使用自定义错误处理程序处理解析致命错误?

jdi*_*ias 70

实际上你可以处理解析和致命错误.确实,用set_error_handler()定义的错误处理函数不会被调用.这样做的方法是使用register_shutdown_function()定义一个关闭函数.以下是我在我的网站上工作的内容:

文件prepend.php(此文件将自动添加到所有php脚本).有关将文件预先添加到PHP的提示,请参见下文.

set_error_handler("errorHandler");
register_shutdown_function("shutdownHandler");

function errorHandler($error_level, $error_message, $error_file, $error_line, $error_context)
{
$error = "lvl: " . $error_level . " | msg:" . $error_message . " | file:" . $error_file . " | ln:" . $error_line;
switch ($error_level) {
    case E_ERROR:
    case E_CORE_ERROR:
    case E_COMPILE_ERROR:
    case E_PARSE:
        mylog($error, "fatal");
        break;
    case E_USER_ERROR:
    case E_RECOVERABLE_ERROR:
        mylog($error, "error");
        break;
    case E_WARNING:
    case E_CORE_WARNING:
    case E_COMPILE_WARNING:
    case E_USER_WARNING:
        mylog($error, "warn");
        break;
    case E_NOTICE:
    case E_USER_NOTICE:
        mylog($error, "info");
        break;
    case E_STRICT:
        mylog($error, "debug");
        break;
    default:
        mylog($error, "warn");
}
}

function shutdownHandler() //will be called when php script ends.
{
$lasterror = error_get_last();
switch ($lasterror['type'])
{
    case E_ERROR:
    case E_CORE_ERROR:
    case E_COMPILE_ERROR:
    case E_USER_ERROR:
    case E_RECOVERABLE_ERROR:
    case E_CORE_WARNING:
    case E_COMPILE_WARNING:
    case E_PARSE:
        $error = "[SHUTDOWN] lvl:" . $lasterror['type'] . " | msg:" . $lasterror['message'] . " | file:" . $lasterror['file'] . " | ln:" . $lasterror['line'];
        mylog($error, "fatal");
}
}

function mylog($error, $errlvl)
{
...do whatever you want...
}
Run Code Online (Sandbox Code Playgroud)

如果他在任何脚本中捕获错误,PHP将调用函数errorHandler().如果错误强制脚本立即关闭,则错误由函数shutdownHandler()处理.

这正在我正在开发的网站上工作.我还没有在生产中测试它.但它目前正在捕捉我在开发过程中发现的所有错误.

我相信存在两次捕获相同错误的风险,每次执行一次.如果我在函数shutdownHandler()中处理的错误也被函数errorHandler()捕获,则可能发生这种情况.

TODO的:

1 - 我需要使用更好的log()函数来优雅地处理错误.因为我还在开发中,所以我基本上将错误记录到数据库并将其回显到屏幕上.

2 - 为所有MySQL调用实现错误处理.

3 - 为我的javascript代码实现错误处理.

重要笔记:

1 - 我在php.ini中使用以下行自动将上述脚本添加到所有php脚本中:

auto_prepend_file = "/homepages/45/d301354504/htdocs/hmsee/cgi-bin/errorhandling.php"
Run Code Online (Sandbox Code Playgroud)

它运作良好.

2 - 我正在记录并解决所有错误,包括E_STRICT错误.我相信开发一个干净的代码.在开发过程中,我的php.ini文件包含以下行:

track_errors = 1
display_errors = 1
error_reporting = 2147483647
html_errors = 0
Run Code Online (Sandbox Code Playgroud)

当我上线时,我会将display_errors更改为0,以降低用户看到丑陋的PHP错误消息的风险.

我希望这可以帮助别人.

  • 似乎没有处理"Parse Errors"...尝试以下方法:echo"Cat"; 回声"狗"回声"狮子"; (5认同)

Den*_*ovs 30

您可以使用以下代码跟踪这些错误:

(如果它们出现在解析错误,只能抓到其他通过脚本文件include()require(),或把这个代码放到一个auto_prepend_file其他的答案也提到.)

function shutdown() {
    $isError = false;

    if ($error = error_get_last()){
    switch($error['type']){
        case E_ERROR:
        case E_CORE_ERROR:
        case E_COMPILE_ERROR:
        case E_USER_ERROR:
            $isError = true;
            break;
        }
    }

    if ($isError){
        var_dump ($error);//do whatever you need with it
    }
}

register_shutdown_function('shutdown');
Run Code Online (Sandbox Code Playgroud)

  • 你测试过吗? (7认同)
  • 在php 5.3上测试 - win 7.在解析错误时不调用shutdown函数. (6认同)
  • 是的,有一种方法可以捕获E_PARSE!将错误处理函数放在index.php中并包含/ require其他文件应该是站点逻辑! (4认同)
  • 我能够防止显示解析错误的唯一方法是包含包含解析错误的脚本。 (2认同)
  • @LucasBatistussi你能解释一下吗?我将错误处理函数放在`index.php`中,然后使用`include(index.php)`将它包含在我的脚本中.但它仍然无法捕获解析错误(语法错误).我不认为没有将其嵌入php.ini中是可能的. (2认同)

Dan*_*oap 28

简单回答:你做不到.参见手册:

使用用户定义的函数无法处理以下错误类型:E_ERROR,E_PARSE,E_CORE_ERROR,E_CORE_WARNING,E_COMPILE_ERROR,E_COMPILE_WARNING,以及调用set_error_handler()的文件中引发的大部分E_STRICT.

对于其他每个错误,您都可以使用 set_error_handler()

编辑:

既然看起来有关于这个主题的讨论,关于使用register_shutdown_function,我们应该看看处理的定义:对我来说,处理错误意味着捕获错误并以一种"好"的方式做出反应用户底层数据(数据库,文件,Web服务等).

使用register_shutdown_function您无法处理调用它的代码中的错误,这意味着代码仍然会在发生错误时停止工作.但是,您可以向用户显示错误消息而不是白页,但是您不能回滚代码在失败之前执行的任何操作.

  • 实际上,您可以使用用户定义的函数处理这些错误.您所要做的就是定义register_shutdown_function.请参阅下面的答案,了解我在网站上实施的工作示例. (4认同)

Cre*_*voc 11

来自PHP.net上的评论页面http://www.php.net/manual/en/function.set-error-handler.php

我意识到这里有一些人提到你无法捕获解析错误(类型4,E_PARSE).这不是真的.这是我的方式.我希望这可以帮助别人.

1)在Web根目录中创建"auto_prepend.php"文件并添加:

<?php 
register_shutdown_function('error_alert'); 

function error_alert() 
{ 
        if(is_null($e = error_get_last()) === false) 
        { 
                mail('your.email@example.com', 'Error from auto_prepend', print_r($e, true)); 
        } 
} 
?> 
Run Code Online (Sandbox Code Playgroud)

2)然后将此"php_value auto_prepend_file /www/auto_prepend.php"添加到Web根目录中的.htaccess文件中.

  • 确保更改电子邮件地址和文件路径.


Mel*_*lsi 5

根据我的经验,您可以捕获所有类型的错误,隐藏默认错误消息并显示您自己的错误消息(如果您愿意).下面列出了您需要的东西.

1)初始/顶级脚本,让我们index.php在您存储自定义错误处理函数的地方调用它.自定义错误函数处理程序必须保持在顶部,以便它们捕获低于它们的错误,"低于"我的意思是在包含文件中.

2)假设这个顶级脚本没有错误必须是真的!这非常重要,在index.php找到自定义错误处理函数时,您无法捕获致命错误index.php.

3)Php指令(也必须在其中找到index.php) set_error_handler("myNonFatalErrorHandler");#in为了捕获非致命错误 register_shutdown_function('myShutdown');#in为了捕获致命错误 ini_set('display_errors', false);#in to to to hide to php向用户显示错误 ini_set('log_errors',FALSE);#assuming我们记录错误我们自己 ini_set('error_reporting', E_ALL);#We我想报告所有的错误

在生产中(如果我没有错)我们可以保持ini_set('error_reporting', E_ALL);原样以便能够记录错误,同时ini_set('display_errors', false);确保没有错误显示给用户.

至于我正在谈论的两个功能的实际内容,myNonFatalErrorHandler并且myShutdown,我不在此处放置详细内容以保持简单.此外,其他访客已经提供了很多例子.我只是表现出一个非常简单的想法.

function myNonFatalErrorHandler($v, $m, $f, $l, $c){
 $some_logging_var_arr1[]="format $v, $m, $f, ".$err_lvl[$l].", $c the way you like";
 //You can display the content of $some_logging_var_arr1 at the end of execution too.
}

function myShutdown()
{
  if( ($e=error_get_last())!==null ){
      $some_logging_var_arr2= "Format the way you like:". $err_level[$e['type']].$e['message'].$e['file'].$e['line'];
  }
//display $some_logging_var_arr2 now or later, e.g. from a custom session close function
}
Run Code Online (Sandbox Code Playgroud)

至于$ err_lvl它可以是:

$err_lvl = array(E_ERROR=>'E_ERROR', E_CORE_ERROR=>'E_CORE_ERROR', E_COMPILE_ERROR=>'E_COMPILE_ERROR', E_USER_ERROR=>'E_USER_ERROR', E_PARSE=>'E_PARSE', E_RECOVERABLE_ERROR=>'E_RECOVERABLE_ERROR', E_WARNING=>'E_WARNING', E_CORE_WARNING=>'E_CORE_WARNING', E_COMPILE_WARNING=>'E_COMPILE_WARNING',
E_USER_WARNING=>'E_USER_WARNING', E_NOTICE=>'E_NOTICE', E_USER_NOTICE=>'E_USER_NOTICE',E_STRICT=>'E_STRICT');
Run Code Online (Sandbox Code Playgroud)