内容简介:你知道PHP中Exception, Error Handler的这些细节吗?
前言
最近项目中有一个功能需要实现:
调试模式下, 将所有错误提前输出, 再输出页面内容.
为实现上述功能, 需使用到 Exception
, Error
相关 Handler
方法, 发现有许多坑, 故写此文与大家分享.
主要函数
此篇文章重点关注以下几个函数
-
error_reporting()
-
set_error_handler()
-
set_exception_handler()
-
register_shutdown_function()
-
error_get_last()
这有什么难的?
哈~ 如果您现在有标题中的感慨, 那么也请关注以下本文中将重点讲述的问题列表:
-
error_reporting()
与error_get_last()
有什么联系? -
set_error_handler()
与set_exception_handler()
绑定的handler
什么时候才会启动? 它们有什么联系? -
register_shutdown_function()
通常跟Exception/Error
有关系么?
上述问题描述模糊, 因此答案也可能千人千面.
因此, 本文只给出自己的答案与大家分享, 如有问题或不同的见解, 期待与您沟通.
如果以上问题, 并不能引起您的兴趣, 或者您已理解透彻了, 就可以自行右上角小红叉啦~
解疑:
1. error_reporting()
与 error_get_last()
有什么联系?
link:PHP.net – error_reporting()
link:PHP.net – error_get_last()
-
int error_reporting ([ int $level ] )
大家应该再熟悉不过了, 因此不再赘述. -
array error_get_last ( void )
获取最后发生的错误.
这两个函数在字面上关联性并不强, 但请观察以下代码及输出
<?php error_reporting(E_ALL & ~E_NOTICE); $a = $b; //E_NOTICE print_r(error_get_last()); /* output: Array ( [type] => 8 [message] => Undefined variable: b [file] => /app/t.php [line] => 3 ) */
error_get_last()
虽然说明了获取最后发生的错误, 实际上也是如此. 但却没有说明, 被 error_reporting()
忽略掉的错误是否有可能被获取到, 因此, 当我们使用 error_get_last()
时需要注意我平时忽略掉的错误, 如: E_DEPRECATED
2. set_error_handler()
与 set_exception_handler()
绑定的 handler
什么时候才会启动? 它们有什么联系?
link:PHP.net – set_error_handler()
link:PHP.net – set_exception_handler()
-
mixed set_error_handler ( callable $error_handler [, int $error_types = E_ALL | E_STRICT ] )
设置用户自定义的错误处理函数.
通常在PHP脚本运行过程中, 出现一些非中断性错误时触发.
我们会用这个来记录错误日志或直接输出等操作.
注意:
-
FALSE
: 标准的错误处理依然会被执行(标准错误处理根据 display_errors = true/false 决定是否输出到stderr
)
-
参数
$error_types
大多设定为error_reporting()
, 但建议设定为E_ALL
, 具体哪些错误需要被处理, 哪些不需要, 在handler
内进行判断明显更加灵活. -
以下级别的错误不能由用户定义的函数来处理: E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING,和在 调用 set_error_handler() 函数所在文件中产生的大多数 E_STRICT
-
handler
被触发后, 并不会中断PHP运行. -
bool error_handler ( int $errno , string $errstr [, string $errfile [, int $errline [, array $errcontext ]]] )
注意error_handler
的返回值:
callable set_exception_handler ( callable $exception_handler )
设置用户自定义的异常处理函数
设置默认的异常处理程序,用于没有用 try/catch 块来捕获的异常。 在 exception_handler 调用后异常会中止。
注意:
注意点中2, 3项轻描淡写了一下 PHP 5/PHP 7
之间的不同却透露出重要的消息(坑..)
PHP 7
中, exception_handler
不再只接受 Exception
了, 并且接收了 Error
错误.
link:PHP.net –PHP7 Errors列表
-
exception_handler
调用后异常会中止(脚本终止). -
自PHP 7 以来,大多数错误抛出 Error 异常,也能被捕获。 Error 和 Exception 都实现了 Throwable 接口。
因此, set_error_handler()
与 set_exception_handler()
之间的关系也迎刃而解:
-
PHP 5
: -
set_error_handler()
: 负责非中断行错误. -
set_exception_handler()
: 负责没有被catch的异常(会中断). -
Fatal Error
等: 并不会被两者管理, 正常输出到屏幕上(弊端). -
PHP 7
: -
set_error_handler()
: 负责非中断行错误. -
set_exception_handler()
: 负责没有被catch的异常,Error
(会中断) -
Fatal Error
等: 由set_exception_handler()
管理.
3. register_shutdown_function()
通常跟Exception/Error有关系么?
link:PHP.net – register_shutdown_function()
注册一个 callback ,它会在脚本执行完成或者 exit() 后被调用。
根据说明可以得出结论, 它与 Exception/Error
完全没关系
.
提出这个问题, 主要是因为, 在 PHP5
中 Fatal Error
并没有明确的接收地点, 所以我们通常配合 error_get_last()
来接收 Fatal Error
<?php register_shutdown_function('shutdown_function'); unknown_function(); function shutdown_function() { print_r(error_get_last()); } /* output: Array ( [type] => 1 [message] => Uncaught Error: Call to undefined function unknown_function() in /app/t.php:3 Stack trace: #0 {main} thrown [file] => /app/t.php [line] => 3 ) */
然而随着 PHP 7
的到来, Error
已经可以被 set_exception_handler()
捕捉了, 再通过 error_get_last()
就多余了. shutdown
中更多的是一些版本冗余的工作.
栗子
前言中的需求: 调试模式下, 将所有错误提前输出, 再输出页面内容.
以下是demo, 省去了环境判断(debug环境), 大家可以根据下面这段代码, 了解本文中所说的各种 handler
的触发和调用情况.
<?php /* 要求: 将所有异常打印在屏幕最上方 */ /* Fatal Error 中断脚本 -> shutdown_handler */ //设置错误级别 define("END_ERRORS", '--END ERRORS--' . PHP_EOL . PHP_EOL); ini_set('display_errors', true); ini_set('error_reporting', E_ALL & ~E_DEPRECATED); set_error_handler('usr_err_handler', error_reporting()); //注册错误处理函数 set_exception_handler('usr_ex_handler'); //注册异常处理函数 register_shutdown_function('shutdown_handler'); //注册会在php中止时执行的函数 $global_errors = []; //用于记录所有错误 $errnos = [ //错误级别 0 => 'ERROR',//PHP7 ERROR的CODE 1 => 'E_ERROR',//FATAL ERROR(PHP5), E_ERROR 2 => 'E_WARNING', 4 => 'E_PARSE', 8 => 'E_NOTICE', 16 => 'E_CORE_ERROR', 32 => 'E_CORE_WARNING', 64 => 'E_COMPILE_ERROR', 128 => 'E_COMPILE_WARNING', 256 => 'E_USER_ERROR', 512 => 'E_USER_WARNING', 1024 => 'E_USER_NOTICE', 2048 => 'E_STRICT', 4096 => 'E_RECOVERABLE_ERROR', 8192 => 'E_DEPRECATED', 16384 => 'E_USER_DEPRECATED', 30719 => 'E_ALL', ]; function reset_errors() { global $global_errors; $global_errors = []; } function get_errnostr($errno) { global $errnos; return $errnos[$errno]; } function set_errnos($errno, $errstr) { global $global_errors; $global_errors[] = [ 'errno' => $errno, 'errnostr' => get_errnostr($errno), 'errstr' => $errstr, ]; } function print_errors($prefix) { global $global_errors; foreach ($global_errors as $err) {//由于handler中依然有可能有error 因此放最后 printf("[%s]: %s, %d, %s/n", $prefix, $err['errnostr'], $err['errno'], $err['errstr']); } } //用户异常处理函数 (进来就中断脚本) PHP5只有Exception进来 PHP7Error和Exception //PHP7中 void handler (Throwable $ex) 可捕获Error和Exception两种异常, 暂不管 //http://php.net/manual/en/language.errors.php7.php PHP7 Error阅读 //内部如果有Error则触发Error函数, 再回到错误行继续执行 function usr_ex_handler($ex) { $content = ob_get_clean(); //让Exception/Error提前展示 print_errors('EX ERROR'); reset_errors(); $errnostr = get_errnostr($ex->getCode()); $errno = $ex->getCode(); $errstr = $ex->getMessage(); if ($ex instanceof Exception) { printf("[EXCEPTION]: %s, %d, %s/n", $errnostr, $errno, $errstr); } else {//针对PHP7 $ex instanceof Error printf("[EX FATAL ERROR]: %s, %d, %s/n", $errnostr, $errno, $errstr); } //由于handler中依然有可能有error 因此放最后 print_errors('EX ERROR'); reset_errors(); echo END_ERRORS; echo $content; return; } //用户错误处理函数 //E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING不能被用户处理 function usr_err_handler($errno, $errstr, $errfile, $errline, $errcontext) { set_errnos($errno, $errstr); return true; //如果函数返回 FALSE,标准错误处理处理程序将会继续调用。 } //用户PHP终止函数 function shutdown_handler() { $content = ob_get_clean(); //让Exception/Error提前展示 $err = error_get_last();//检查一下是否有遗漏掉的错误 php5 fatal error if ($err['type'] & error_reporting()) { set_errnos($err['type'], $err['message']); } print_errors('ST ERROR'); reset_errors(); echo $content; } ob_start(); echo 'Main function...', PHP_EOL; //搞事情 //throw new Exception('这是一个异常'); trigger_error('这是一个用户error');//E_USER_NOTICE if (version_compare(PHP_VERSION, '7.0.0') >= 0) { mcrypt_encrypt();//E_WARNING, E_DEPRECATED } else { mysql(); } unknown_function(); //fatal error $content = ob_get_clean(); //优先输出错误 print_errors('MA ERROR'); if (!empty($global_errors)) { echo END_ERRORS; } reset_errors(); //输出正文内容 echo $content;
以上所述就是小编给大家介绍的《你知道PHP中Exception, Error Handler的这些细节吗?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 几个你不知道的 dubbo 注册中心细节
- 你所不知道的 CSS 阴影技巧与细节
- Mybatis源码详解系列(四)--你不知道的Mybatis用法和细节
- 重学前端学习笔记(六)--JavaScript类型有哪些你不知道的细节?
- Flutter platform view 避坑指南,你应该知道的技术细节之性能篇
- MQTT Essential 细节笔记总结(深入理解MQTT细节)
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Servlet和JSP学习指南
Budi Kurniawan / 崔毅、俞哲皆、俞黎敏 / 机械工业出版社华章公司 / 2013-4-14 / 59.00元
本书是系统学习Servlet和JSP的必读之作。由全球知名的Java技术专家(《How Tomcat Works》作者)亲自执笔,不仅全面解读Servlet 和JSP 的最新技术,重点阐述Java Web开发的重要编程概念和设计模型,而且包含大量可操作性极强的案例。 本书共18章:第1章介绍Servlet API和几个简单的Servlet;第2章讨论Session追踪,以及保持状态的4种技术......一起来看看 《Servlet和JSP学习指南》 这本书的介绍吧!