PHP:如何使用set_error_handler()来处理除通知外的所有错误?

15

我对如何正确使用set_error_handler()感到困惑,而且php文档并没有帮助我澄清问题。

我希望它能够将尽可能多的错误发送给我,除了注意事项。

我有以下代码

<?php

if (TRAP_ERRORS) { 
// True on production, false in development, where errors are just echoed out.
    set_exception_handler('globalExceptionHandler');
    set_error_handler('globalErrorHandler', E_USER_WARNING);
}

function globalExceptionHandler($e) {
    //log and email stuff here
}

function globalErrorHandler($errno, $errstr, $errfile, $errline) {
    switch ($errno) {
        case E_NOTICE:
        case E_USER_NOTICE:
            $errors = "Notice";
            break;
        case E_WARNING:
        case E_USER_WARNING:
            $errors = "Warning";
            break;
        case E_ERROR:
        case E_USER_ERROR:
            $errors = "Fatal Error";
            break;
        default:
            $errors = "Unknown Error";
            break;
    }

    error_log(sprintf("PHP %s:  %s in %s on line %d", $errors, $errstr, $errfile, $errline));
    $msg = "ERROR: [$errno] $errstr\r\n".
        "$errors on line $errline in file $errfile\r\n";

    sendErrorEmail($msg);
    showErrorPage();

    exit(1);
}

function sendErrorEmail($p_errorMsg) {
    // Parse and sent out the error email...
}

function showErrorPage() {
    // Redirect to an error page.
}

?>
这是我的当前设置set_error_handler('globalErrorHandler', E_USER_WARNING);,但似乎有问题,因为它不能处理trigger_error()错误。我认为这是因为参数应该是一个位掩码而不仅仅是单个错误级别,但我不确定如何设置它以处理最大数量的错误/信息(除了通知)。我看到有使用E_ALL的示例,但这实际上会导致包括全局错误处理程序内容的任何代码出错。那么,我该如何使用set_error_handler来处理最大数量的信息,使得我的自定义错误处理程序能够自动发送电子邮件直接处理此类问题,而无需稍后查看日志?
4个回答

16
set_error_handler('some_handler',E_ALL & ~E_NOTICE & ~E_USER_NOTICE);

或者,如果你真的想要全部,

set_error_handler('some_handler',-1 & ~E_NOTICE & ~E_USER_NOTICE);

或者,您可以将其设置为使用所有错误,并且如果它们不在error_reporting中(您将其设置为与上面一行相同的值),则只需忽略它即可,此时@运算符也能正常工作:

....
if(!($errno & error_reporting())) return true;
switch($errno){
....

等等,那么将其设置为error_reporting()的返回值也可以工作,对吧?我认为这基本上就是我想要的,因为我已经报告了除通知以外的所有内容。 - Kzqai
是的,那么您可以省略第二个参数,只需在其中进行错误报告检查即可。 - Wrikken
2
哦,我是指作为第二个参数,例如 set_error_handler('some_handler', error_reporting()); - Kzqai

3

如果不需要第二个参数,或者想传入默认值E_ALL | E_STRICT(所有错误和严格模式错误,别被这里的按位OR搞混了),可以省略第二个参数。

此外,你可以通过使用register_shutdown_function()error_get_last()技巧来“捕获”致命错误,这在这里有演示:Handle fatal errors in PHP using register_shutdown_function()


2
$error_type 是一个整数,你可以使用掩码设置它。如果你想要除 E_NOTICE 以外的所有错误都使用错误处理程序,可以使用以下其中之一:
set_error_handler('globalErrorHandler', E_ALL ^ E_NOTICE);
set_error_handler('globalErrorHandler', E_ALL & ~E_NOTICE);

如果您还想排除E_USER_NOTICE,那么:
set_error_handler('globalErrorHandler', E_ALL ^ (E_NOTICE | E_USER_NOTICE));
set_error_handler('globalErrorHandler', E_ALL & ~E_NOTICE & ~E_USER_NOTICE);

请注意位运算符"&"、"~"和"|"的使用,详见PHP位运算符手册
请注意,在调用set_error_handler函数之前出现的错误或编译器错误可能无法被捕获。详见PHP set_error_handler文档

0
如何使用定时任务让服务器自动发送错误日志文件给您,而不是在应用程序内部处理它。

已经通过logcheck和logwatch定期执行,使用cron...这意味着当用户发生错误时,我需要通过日志查找才能了解到,因此对于更重要的问题,我需要一个更及时的响应机制。 - Kzqai
这就是为什么我使用自定义错误处理程序的原因 - 用于管理自定义日志记录(例如,带有完整的回溯)和通知。 - Wiseguy
让我们换个方式来混合它; 制作一个文件比较小脚本,它保留最后一次日志的副本,并将其与新日志进行比较,如果有更改,则触发电子邮件;否则不会。频率可以设置得稍低一些;例如每15分钟左右.. 1kb的脚本不会造成太多麻烦。否则,对于像上面那样的错误报告,您可以使用异常处理来处理所有类型的错误,并在异常捕获中执行任何想要执行的操作,或者创建一个异常类,该类是所有类的父类,以为您完成该工作。 - Faisal Nasim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接