正确认识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_WARNINGE_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,以告知客户端服务端存在异常。

发表评论

电子邮件地址不会被公开。