一,错误的触发
错误的触发方式有:
- 系统触发错误(比如有未捕获的异常,或参数类型不正确)
- 用户触发错误trigger_error
特别地,set_exception_handler是用于未捕获异常的自动处理函数,如果注册了回调函数,则正常系统未捕获异常会在调用此函数后视作已处理异常;否则将触发未捕获异常的E_ERROR.
用户级别错误属于E_USER系列,其他的属于系统错误。具体地有:
(来源:)
Value | Constant | Description | Note |
---|---|---|---|
1 | E_ERROR () | Fatal run-time errors. These indicate errors that can not be recovered from, such as a memory allocation problem. Execution of the script is halted. | |
2 | E_WARNING () | Run-time warnings (non-fatal errors). Execution of the script is not halted. | |
4 | E_PARSE () | Compile-time parse errors. Parse errors should only be generated by the parser. | |
8 | E_NOTICE () | Run-time notices. Indicate that the script encountered something that could indicate an error, but could also happen in the normal course of running a script. | |
16 | E_CORE_ERROR() | Fatal errors that occur during PHP's initial startup. This is like an E_ERROR, except it is generated by the core of PHP. | |
32 | E_CORE_WARNING() | Warnings (non-fatal errors) that occur during PHP's initial startup. This is like an E_WARNING, except it is generated by the core of PHP. | |
64 | E_COMPILE_ERROR() | Fatal compile-time errors. This is like an E_ERROR, except it is generated by the Zend Scripting Engine. | |
128 | E_COMPILE_WARNING() | Compile-time warnings (non-fatal errors). This is like an E_WARNING, except it is generated by the Zend Scripting Engine. | |
256 | E_USER_ERROR() | User-generated error message. This is like an E_ERROR, except it is generated in PHP code by using the PHP function . | |
512 | E_USER_WARNING() | User-generated warning message. This is like an E_WARNING, except it is generated in PHP code by using the PHP function . | |
1024 | E_USER_NOTICE() | User-generated notice message. This is like an E_NOTICE, except it is generated in PHP code by using the PHP function . | |
2048 | E_STRICT () | Enable to have PHP suggest changes to your code which will ensure the best interoperability and forward compatibility of your code. | Since PHP 5 but not included in E_ALL until PHP 5.4.0 |
4096 | E_RECOVERABLE_ERROR() | Catchable fatal error. It indicates that a probably dangerous error occured, but did not leave the Engine in an unstable state. If the error is not caught by a user defined handle (see also ), the application aborts as it was an E_ERROR. | Since PHP 5.2.0 |
8192 | E_DEPRECATED() | Run-time notices. Enable this to receive warnings about code that will not work in future versions. | Since PHP 5.3.0 |
16384 | E_USER_DEPRECATED() | User-generated warning message. This is like an E_DEPRECATED, except it is generated in PHP code by using the PHP function . | Since PHP 5.3.0 |
32767 | E_ALL () | All errors and warnings, as supported, except of level E_STRICT prior to PHP 5.4.0. | 32767 in PHP 5.4.x, 30719 in PHP 5.3.x, 6143 in PHP 5.2.x, 2047 previously |
二,错误的捕获
一旦错误被触发,它将被捕获并被处理;随之而来的,可能是程序的继续执行,或是程序的终止。一般地说,与这个过程相关的函数和配置有:error_reporting,display_errors,log_errors,set_error_handler。总的来说,错误将会被优先发给用户自定义的错误处理函数,然后交由系统处理。
总的来说,这些错误,有的会只经过自定义函数处理,有的会只经过系统处理,有的是经过自定义函数处理过后,然后再交由系统处理。
预先步骤:
检查是否有错误控制符(@),如果有,将error_reporting的返回值,强制设为0.
1)交由自定义函数处理的情况是(必须同时满足)
a.不属于E_ERROR,E_PARSE,E_CORE_ERROR,E_CORE_WARNING,E_COMPILE_ERROR,E_COMPILE_WARNING,和大部分的E_STRICT的错误类型(我们姑且称之为”严重错误“和”普通错误“)
b.注册了一个set_error_handler处理函数
c.set_error_handler的第二个参数,与该错误类型的整数位相与,结果不为0
其他情况,转入步骤三
2)调用set_error_handler函数对错误进行处理,满足以下情况转入步骤三,其他情况跳出错误处理过程:
a.set_error_handler处理结束之后,返回的结果为false值
3)系统处理的过程是:
a.查看error_reporting的值,与错误类型的整数进行位相与,如果结果为0,转入步骤四
b.如果display_errors为true,将错误输出到标准输出流
c.如果log_errors为true,将结果记录进日志(由error_log配置决定日志位置,如果没有)
4)最后一个步骤,决定程序的走向
a.如果是非致命性错误,程序将继续执行
b.如果是致命性错误,则
(1)如果使用register_shutdown_function注册了结束函数,调用结束函数,否则直接转入下面步骤
(2)符合以下情况则将http状态改为500
(a)display_errors为false
(b)在错误发生前,尚未发送header数据
(c)目前的http状态为200
(3)结束程序
三,设计健壮的错误处理方法
这个错误处理方法,要达成以下目标:
1)非常健壮,能够在触发致命性错误的时候,依旧可以处理,而不是直接退出
2)非常安全,不会向终端用户泄露关于程序处理过程的信息
3)非常友好,终端用户看到尽可能少的信息而开发者能看到尽可能多的信息
我的设计思路如下:
0)总体思路:首先,我们必须知道,一致的意外情况处理方法非常重要,而php既有error又有exception的方式是历史原因。所以,第一,不要使用trigger_error来触发自定义错误,而应当抛出异常;第三,系统的普通错误信息由于是历史原因,无法改写,应当调用set_error_handler包装为异常予以处理;第三,系统的严重错误可以调用register_shutdown_function包装成异常予以处理。这样的话,所有的错误和异常都被当作异常,通过一致的方式,予以处理。
对于错误的信息,应当调用debug_backtrace进行详细分析。设计的最终步骤如下:
1)我们观察到系统的错误处理过程,是display_errors和log_errors,这两种我们都可以在自定义的错误处理函数中予以解决,因此,第一步,关闭系统错误处理ini_set('display_errors',false),ini_set('log_errors',false)。为什么不直接error_reporting(0)呢?因为我们可以利用error_reporting来自定义忽略一些错误,更重要的是为了@操作符也能够发挥应有的效果。
2)调用set_exception_handler()定义一个异常的处理函数ExceptionHandler(),这个函数主要用于处理未经处理的异常,尤其重要的是,它将用来处理我们的错误异常ErrorException(包括致命性错误)。这是我们的核心处理部分。
3)通过set_error_handler,普通错误全部捕获,调用error_reporting查看是否应该忽略该错误,如果不应当忽略,则在error_handler内部将错误包装为ErrorException,调用ExceptionHandler($error)。
4)注册一个register_shutdown_function,处理致命性错误发生的行为,调用ExceptionHandler。
通过以上步骤,可以建立起一个安全高效和稳健的错误处理流程。此外,还可以通过配置,对生产和开发环境使用有所区别的方式。
最后,推荐使用facebook出品的xhprof来监控系统的性能。