正确认识php7错误与异常
最近写了一个PHP框架,对PHP7的错误与异常处理有了更深刻的认识,分享给大家。
相同点
错误和异常都是PHP用来报告问题的方式。
本质差异
异常抛出后,如果没有try catch捕获,代码就会立即停止执行。
错误发生后,只有FATAL级别的错误会终止代码执行,其他错误不会终止代码。
PHP错误
错误分类
错误分级别,主要分两类:致命错误和非致命错误。
例如 E_ERROR、E_CORE_ERROR等都是致命错误,代码立即终止。
例如 E_NOTICE、E_WARNING等都是非致命错误,代码继续往下执行。
错误级别
通过error_reporting可以指定哪些错误可以报告出来,所谓的报告出来就是指可以打印到屏幕上。
无论致命还是非致命错误,都同样可以受到该函数的约束。
当然最终能否打印到屏幕还受到display_errors选项的影响,后面会说。
错误捕获
set_error_handler可以捕获非致命错误,比较特别的是像E_USER_ERROR这种用户抛出来的致命错误,仍旧可以被set_error_handler捕获,而普通E_ERROR致命错误则不能被set_error_handler捕获。
不会受到error_reporting影响,只要是非致命错误就可以被捕获,无论错误本身是否允许输出。
官方文档说,下面这些致命错误是无法被捕获的(E_USER_ERROR这种致命错误仍旧是可以被set_error_handler捕获的,这里再次强调):
E_ERROR
、 E_PARSE
、 E_CORE_ERROR
、 E_CORE_WARNING
、E_COMPILE_ERROR
、 E_COMPILE_WARNING。
错误显示
当错误类型在error_reporting允许报告的范围内时,最终错误能否打印到屏幕收到display_errors的影响,可以做到错误日志整体输出的开关控制。
错误日志
和display_errors同样地位,你可以通过log_errors让错误输出到文件,而不是打印到屏幕,当然还是受到error_reporting的影响。
错误抑制
通过@可以抑制错误输出,它的效果相当于old = error_reporting(0); xxx; error_reporting(old); ,其实还是在影响是否输出,并不影响set_error_handler回调。
一般建议别用这个,除非你知道你在做什么。
PHP异常
exception
我们非常熟悉继承自Exception类的异常,如果不try catch会导致程序终止运行。
异常捕获
可以通过set_exception_handler来捕获开发者没有try catch住的异常。
这里有一个误区,就是认为set_exception_handler捕获异常后,代码可以继续向下执行,这当然是错误的认识!
set_exception_handler只是让你有最后的机会处理一下善后而已!
异常->致命错误
如果你没有捕获异常,也没有设置set_exception_handler,那么异常会被转换成一个FATAL ERROR(致命错误),可能会打印到屏幕上。
异常只是一个异常而已,错误才是用户要看的,所以未捕获的异常转换成错误是容易理解的。
错误转异常
PHP7正在主导错误向异常的发展路线,所以很多以前的错误都被换成了异常。
所以在PHP7之后,我们应该认真的处理异常,因为错误信息被直接封装到了异常对象中,而不是通过原有的错误报告机制反馈。(异常没捕获,还是会被转成FATAL ERROR打印出来!)
最佳实践
总是error_reporting(E_ALL),并根据调试环境 Or 生产环境决定display_errors=true/false。
不必设置set_error_handler,致命错误抓不住,非致命错误代码照常跑,因此只需要在调试环境通过display_errors=true打印到屏幕上,在生产环境display_errors=false不打印到屏幕上,这样就满足需求了。
总是设置set_exception_handler,并至少在回调中设置http code=500,以告知客户端服务端存在异常。
如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~
