PHP的全局错误处理详解
本文目的
php的全局错误处理,在开发项目的时候很有用,可以帮助开发者快速定位一些问题,提高工作效率。默认情况下,全局错误会直接输出,但是最近开发时使用的一个框架库对全局错误处理进行了设定,导致很多错误信息没有输出,在定位问题上有一定的耗时。所以,研究了一下此库的实现,发现它设定了error_reporting和set_error_handler,导致此现象。现在记录一下这两个函数的用法,作为备忘录。
背景
php没有类型检测,开发人员比较容易输入错误单词,引起致命错误,最终导致脚本停止执行。如果这个时候,没有得到任何错误消息,那么会是一件很痛苦的事情。你不得不从脚本的第一行代码开始调试,在成千上万行的代码中不断的print或者echo,直到定位到这个输错的单词。然后,有不得不原路返回,将先前添加的print或echo全部删除。这时一件及其枯燥乏味的工作。
一般情况
正常情况下,php会将致命错误直接输出,会将错误的出处(文件地址,行号)和原因等输出,这样,开发着可以很方便的定位到问题。
但是有些时候,可能由于php.ini的设置问题,可能是第三方框架配置的问题,导致这些信息没有输出,那么此时,必须学会自己设置相关参数,输出这些错误信息,帮助快速定位问题。
error_reporting
error_reporting是一个php的全局配置参数,在php.ini中。用于配置错误输出级别,参数是比特位,可以用来设置错误输出的级别,下面是从php.ini中copy出来的信息:
; error_reporting is a bit-field. or each number up to get desired error ; reporting level ; e_all - all errors and warnings (doesn't include e_strict) ; e_error - fatal run-time errors ; e_recoverable_error - almost fatal run-time errors ; e_warning - run-time warnings (non-fatal errors) ; e_parse - compile-time parse errors ; e_notice - run-time notices (these are warnings which often result ; from a bug in your code, but it's possible that it was ; intentional (e.g., using an uninitialized variable and ; relying on the fact it's automatically initialized to an ; empty string) ; e_strict - run-time notices, enable to have php suggest changes ; to your code which will ensure the best interoperability ; and forward compatibility of your code ; e_core_error - fatal errors that occur during php's initial startup ; e_core_warning - warnings (non-fatal errors) that occur during php's ; initial startup ; e_compile_error - fatal compile-time errors ; e_compile_warning - compile-time warnings (non-fatal errors) ; e_user_error - user-generated error message ; e_user_warning - user-generated warning message ; e_user_notice - user-generated notice message ; ; examples: ; ; - show all errors, except for notices and coding standards warnings ; ;error_reporting = e_all & ~e_notice ; ; - show all errors, except for notices ; ;error_reporting = e_all & ~e_notice | e_strict ; ; - show only errors ; ;error_reporting = e_compile_error|e_recoverable_error|e_error|e_core_error ; ; - show all errors except for notices and coding standards warnings ; error_reporting = e_all & ~e_notice
默认情况下,php会输出所有错误信息,除了notice。同样,php标准函数中提供了名称相同的函数error_reporting(int $level),用于在php脚本中,完成同样的功能。这样将不会影响其他程序。值得注意的是,$level为0的时候是关闭错误输出,也就是任何错误都不会输出。
set_error_handler
php的默认错误处理是将消息输出。但是,有时候需要定义一些其他操作,这时就需要自定义错误处理函数。php提供内置函数set_error_handler可以帮助我们注册自己的错误处理函数。函数原型如下:
mixed set_error_handler ( callback $error_handler [, int $error_types = e_all | e_strict ] )
值得注意的是,即使注册了错误处理函数,默认的行为仍然会执行,也就是错误出现时,仍然会输出错误信息,所以需要在程序中显示的将错误级别设置为0,然后在注册自己的的错误处理函数。这种方式,在生产环境下,尤其重要,因为即时出错,敏感内部错误信息也不会暴露给潜在的恶意用户。还有很重要的一点需要指出,自定义错误处理函数不能处理fatal error(比如编译错误)。下面是一个使用自定义错误处理函数的列子:
<?php error_reporting (0); function error_handler ($error_level, $error_message, $file, $line) { $exit = false; switch ($error_level) { case e_notice: case e_user_notice: $error_type = 'notice'; break; case e_warning: case e_user_warning: $error_type = 'warning'; break; case e_error: case e_user_error: $error_type = 'fatal error'; $exit = true; break; default: $error_type = 'unknown'; $exit = true; break; } printf ("%s: %s in %s on line %d\n", $error_type, $error_message, $file, $line); if ($exit) { die(); } } set_error_handler ('error_handler'); //new nonexist(); echo $novar; echo 3/0; trigger_error ('trigger a fatal error', e_user_error); new nonexist(); ?>
执行此脚本可以得到下面的输出:
notice: undefined variable: novar in /your/php_demo_file.php on line 40 warning: division by zero in /your/php_demo_file.php on line 41 fatal error: trigger a fatal error in /your/php_demo_file.php on line 42
可以看到,最后的“new noexistclass()”的异常,没有被自定义的错误处理函数捕获。
最后,捎带提一下,set_exception_handler注册顶层的异常处理,在web一用中,可以设定一下,然后统一的跳转到错误处理页面。