PHP的错误和异常处理


php程序的运行,会产生不同级别的错误和异常信息,了解这些对我们写出健壮的程序还是很有帮助的。

而且有时候我们确实面对一些关于提现错误信息的具体需求。

比如: 忽略掉无关紧要的错误信息,对于中断程序的错误和异常信息,在显示上做区别处理,区别条件可以是是否为 DEBUG调试模式、异常码 等等。。

下面主要整理这几块内容: php的错误级别 、error_reporting 和 display_errors 、非致命错误处理 、致命错误处理 、异常处理


php的错误级别

我本地的php版本是php7.0 . 配置文件 php.ini 中的错误级别截图如下。

1

官网也有: 错误处理 - 预定义常量

1

E_ALL 的话低版本是不包括 E_SCRIPT 的,有点小差别,不过影响不大。

可以发现这些错误级别值的规律,就是15位的二进制数转成10进制的结果。

000000000000001  =》  1

000000000000010  =》  2

000000000000100  =》  4

000000000001000  =》  8

.......

100000000000000  =》  16384

E_ALL 就是这些错误级别的和。 111111111111111 =》 32767

可以使用 decbin 函数将10进制转二进制输出这些错误级别常量查看。


error_reporting 和 display_errors

设置PHP错误报告和是否输出错误信息

设置PHP错误报告

error_reporting 是php的保存级别设置属性。值的话,就是上面这些错误级别的搭配。

error_reporting 可以在配置文件赋值,如 error_reporting = E_ALL ,也可以在程序中去定义,调用函数 error_reporting

一般常用的就是:

error_reporting(E_ALL)    #报告所有错误
error_reporting(E_ALL & ~E_NOTICE)    #报告除了notice之外的所有错误
error_reporting(E_ERROR | E_WARNING | E_PARSE)    #报告运行时错误

举例解释下 E_ALL & ~E_NOTICE

首先 E_NOTICE 的二进制是 000000000001000 , 使用~取反,就是 111111111110111

再与 E_ALL(111111111111111)进行 & 按位与操作,就得到 111111111110111 ,可以简单理解成每一位1就表示一个错误级别。为0的那一位权重是2的3次方就是8,对应的就是 E_NOTICE

error_reporting ( 0 ); 就是关闭所有PHP错误报告

如果没有设置可选参数 level, error_reporting() 仅会返回当前的错误报告级别

自己稍微理解下,哈哈哈。我都是用 error_reporting(E_ALL & ~E_NOTICE) 。因为我们会关闭掉程序错误显示,改动自己捕捉处理,往下看。


是否输出错误信息

display_errors 这个配置是用于控制PHP是否输出错误信息,值为 On 或者 Off .

在程序中设置的话需要使用 ini_set 函数,比如 ini_set('display_errors','On')

这个配置项应该根据条件来配置:

首先如果有设置自定义错误和异常处理handler,那么可以设置为Off。自己来处理错误信息,打印错误信息或是跳转等等。

没有的话,如果是开发环境(DEBUG)的话,就设置为 On , 线上环境则设置为 Off ,错误信息可能存在敏感信息,不能对外暴露,比如文件路径,入口等。


非致命错误处理

在PHP中,对待 E_WARNING、E_NOTICE、E_COMPILE_WARNING、E_STRICT 等这种非致命的错误,可以使用set_error_handler 函数自定义错误处理程序来处理错误。

set_error_handler ( callable $error_handler [, int $error_types = E_ALL | E_STRICT ] )

使用方法:

$error_handler 传函数名

1


$error_handler 传引用对象和对象方法名数组

1

至于第二个参数 $error_types 和 上面 error_reporting 一样,不过如果你这边设置的错误类型的话,那么产生的这些错误都会被这个自定义的错误程序捕捉到,就会绕过PHP标准错误处理程序了,除非在回调函数 $error_handler 返回了 false .

以下情况的错误不能由用户定义的函数来处理:

 1. 错误级别为 E_ERROR 、 E_PARSE 、 E_CORE_ERROR 、 E_CORE_WARNING 、 E_COMPILE_ERROR 、E_COMPILE_WARNING 

 2. 在 调用 set_error_handler() 函数所在文件中产生的大多数 E_STRICT 。

 3. 在自定义错误程序注册之前的错误。


致命错误处理

致命错误就是指会中断脚本执行的错误,比如漏掉个结尾分号,调用未定义的函数,require_once了不存在的文件等。

致命错误包括 E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE, E_USER_ERROR

因为 set_error_handler 只能捕捉部分非致命的错误,无法对致命错误进行捕捉,所以对待这些致命错误,我们需要再处理一下。


register_shutdown_function(callable $callback[,mixed $parameter[,mixed $...]] )

当我们的脚本执行完成或意外死掉导致PHP执行即将关闭时, register_shutdown_function 这个函数将会被调用.

error_get_last — 获取最后发生的错误

返回了一个关联数组,描述了最后错误的信息,以该错误的 "type"、 "message"、"file" 和 "line" 为数组的键。 

 如果该错误由 PHP 内置函数导致的,"message"会以该函数名开头。 如果还没有错误则返回 NULL 。

 

把二者结合一下,就可以用来捕捉中止脚本的错误捕捉处理程序了。

1

和 set_error_handler 一样也可以传引用对象和对象方法名数组。


异常处理

对于异常处理,我的第一反应就是 try catch 。

不过除了 try catch 外,我们还可以自定义异常处理程序。

set_exception_handler(callable $exception_handler)

设置默认的异常处理程序,用于没有用 try/catch 块来捕获的异常。 在 exception_handler 调用后异常会中止。 

使用方法:

1

和 set_error_handler 一样也可以传引用对象和对象方法名数组。


最后

在测试的过程中,我发现有的致命错误会被 自定义的异常处理程序捕获 ,比如调用未定义的函数这种致命错误。

网上找的答案: 

PHP7实现了一个全局的throwable接口,原来的Exception和部分Error都实现了这个接口(interface), 以接口的方式定义了异常的继承结构。于是,PHP7中更多的Error变为可捕获的Exception返回给开发者,如果不进行捕获则为Error,如果捕获就变为一个可在程序内处理的Exception。这些可被捕获的Error通常都是不会对程序造成致命伤害的Error,例如函数不存。

所以在YPHP的自定义异常处理程序上,我用用错误码加以区别,在抛出异常上会尽量带上其场景的异常码,这个写场景异常码由自己定义。


php


上一篇:YPHP后续的开发方向(长期更)

YPHP框架模型层预想小记:下一篇