php错误处理之set_error_handler增强版
发布于 作者:苏南大叔 来源:程序如此灵动~在本文中,苏南大叔将对上一篇文章中的遗留问题进行进一步叙述。内容主要针对php5中,如何捕获fatal error
而展开。
当然,在php7中,您可能需要的仅仅是set_exception_handler
,用它捕获fatal error
即可,不过本文的内容,对于php7也有一定的学习借鉴意义。上一篇文章的地址是:https://newsn.net/say/php-set_error_handler.html 。
前言
在上一篇的文章中,我们可以知道,在php7中,我们可以使用set_exception_handler
和set_error_handler
,完美捕获错误信息。而在php5中,似乎不是那么的完美,总是有些fatal error
是不能捕获的。这里有个解决方案。苏南大叔称之为set_error_handler增强版
。
error的级别
在php的函数中,有个error_reporting
的函数,它规定了什么样的级别的error
才会report。从这里,我们可以知道error是有级别区别的。具体的信息可以点击这里:http://doc.php.sh/zh/function.error-reporting.html 。
而在上一篇文章中,trigger_error触发的error的级别是:notice,最后的未定义函数触发的error级别是:fatal error。那么对应的php级别名词是:notice=>E_USER_NOTICE,fatal error=>E_ERROR。具体的错误级别说明,可以点击这里查看:http://doc.php.sh/zh/errorfunc.constants.html 。
set_error_handler
不处理E_ERROR
mixed set_error_handler ( callable $error_handler [, int $error_types = E_ALL | E_STRICT ] )
重要的是要记住 error_types 里指定的错误类型都会绕过 PHP 标准错误处理程序, 除非回调函数返回了 FALSE。 error_reporting() 设置将不会起到作用而你的错误处理函数继续会被调用 ―― 不过你仍然可以获取 error_reporting 的当前值,并做适当处理。以下级别的错误不能由用户定义的函数来处理: E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、E_COMPILE_ERROR、 E_COMPILE_WARNING,和在 调用 set_error_handler() 函数所在文件中产生的大多数 E_STRICT。
上述引用内容来自:http://doc.php.sh/zh/function.set-error-handler.html
苏南大叔的解读是:默认参数$error_types
,将所有的错误信息,E_ALL | E_STRICT
都默认绕过php标准错误处理程序,当且仅当回调函数返回false的时候,才会进入默认php标准错误处理程序。无视error_reporting()
的相关设置。
从这里,我们就可以理解php5中,为什么最后的“函数未定义”没有被set_error_handler
捕获了。这个“函数未定义”错误在php7中可以被set_exception_hanlder
捕获。
php5中的解决方案
php5虽然已经是过去时了,但是下面的代码还是有点借鉴意义的。
代码的原理是:在一个单独的include文件里面,定义register_shutdown_function
的回调函数,然后通过分析error_get_last()
获得fatal error
的信息,进而转向错误处理程序。当然,set_error_handler
也会跟随设置。
两者区别就在于:错误处理回调函数,如果是error_get_last()
后触发的,那么return false
或者return true
都没有意义了。因为是先触发的错误,而后进行捕获的。如果是set_error_handler
触发的,那么是先捕获错误,然后再由return false
或者return true
来决定是否触发php标准错误处理程序。
对于error_get_last()
触发的这种错误回调情况,我们需要使用error_reporting(0)
或者@
来抑止标准的错误输出。
代码如下:
error_handler.php:
//error_reporting(0);
register_shutdown_function("shutdown_handler");
function shutdown_handler() {
define('E_FATAL', E_ERROR | E_USER_ERROR | E_CORE_ERROR |
E_COMPILE_ERROR | E_RECOVERABLE_ERROR | E_PARSE);
$error = error_get_last();
if ($error && ($error["type"] === ($error["type"] & E_FATAL))) {
$errno = $error["type"];
$errfile = $error["file"];
$errline = $error["line"];
$errstr = $error["message"];
error_handler($errno, $errstr, $errfile, $errline);
}
}
set_error_handler("error_handler");
function error_handler($errno, $errstr, $errfile, $errline) {
echo "<b>出错了,错误如下:</b><br/><br/>";
echo "代码: $errno <br />\n";
echo "信息: $errstr <br />\n";
echo "文件: $errfile <br />\n";
echo "行号: $errline <br />\n";
return true;
//return false;
}
index.php:
require "error_handler.php";
echo "PHP " . PHP_VERSION . " (" . PHP_OS . ")<br />\n";
//set_error_handler("error_handler");
//throw new Exception('这是个自定义异常exception');
//throw new Exception('这是个带编号的自定义异常exception',1);
//trigger_error("这是个无法捕捉的自定义的错误error");
//throw new Error('这是个带编号的自定义的错误error',2);
@this_is_an_on_purpose_error();
echo "恭喜,没有错误\n";
方案效果截图
通过本增强版方案,php5捕获到了fatal error(代码为1)。
结语
php错误处理,是php程序调试的关键因素之一。但是市面上的各种框架太多,调试方式也不一样。所以掌握背后的原理,就可以万变不离其宗,以不变应万变了。
更多苏南大叔的php相关经验总结,请点击这里查看:https://newsn.net/tag/php/ 。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。