PHP常见概念混淆(八)之错误与异常
PHP 错误
PHP报告错误是为了响应一些内部错误情况,而且通过类型来表示不同的内部错误情况,并且可以通过设置来显示或者记录下来。 PHP错误类型作为PHP核心之错误扩展中的预定义常量存在。
PHP错误最佳实践
- 一定要让 PHP 报告错误;
- 在开发环境中要显示错误;
- 在生产环境中不能显示错误;
- 在开发和生产环境中都要记录错误。
PHP错误类型
PHP错误类型以及错误级别
PHP分为多个错误级别,而且在不同版本中的错误级别有可能不一致,建议使用预定义常量,而不是数字。
值 | 常量 | 说明 |
---|---|---|
1 | E_ERROR | 致命的运行时错误,不可恢复,如位置异常,内存不足等。注意,如果有未被捕获的异常,也是会触发这个级别的。 |
2 | E_WARNING | 运行时警告 (非致命错误)。仅给出提示信息,但是脚本不会终止运行。 |
4 | E_PARSE | 解析错误,在解析PHP文件时产生,并强制PHP在执行前退出 |
8 | E_NOTICE | 运行时通知。表示脚本遇到可能会表现为错误的情况,但是在可以正常运行的脚本里面也可能会有类似的通知。 |
16 | E_CODE_ERROR | 在PHP初始化启动过程中发生的致命错误。该错误类似E_ERROR ,但是是由PHP引擎核心产生的。 |
32 | E_CODE_WARNING | PHP初始化启动过程中发生的警告 (非致命错误) 。类似 E_WARNING ,但是是由PHP引擎核心产生的。 |
64 | E_COMPILE_ERROR | 致命编译时错误。类似E_ERROR , 但是是由Zend脚本引擎产生的。 |
128 | E_COMPILE_WARNING | 编译时警告 (非致命错误)。类似E_WARNING ,但是是由Zend脚本引擎产生的。 |
256 | E_USER_ERROR | 用户产生的错误信息。类似E_ERROR , 但是是由用户自己在代码中使用PHP函数 trigger_error() 来产生的。 |
512 | E_USER_WARNING | 用户产生的警告信息。类似E_WARNING , 但是是由用户自己在代码中使用PHP函数trigger_error() 来产生的。 |
1024 | E_USER_NOTICE | 用户产生的通知信息。类似E_NOTICE , 但是是由用户自己在代码中使用PHP函数 trigger_error() 来产生的。 |
2048 | E_STRICT | 启用 PHP 对代码的修改建议,以确保代码具有最佳的互操作性和向前兼容性。 |
4096 | E_RECOVERABLE_ERROR | 可被捕捉的致命错误。 它表示发生了一个可能非常危险的错误,但是还没有导致PHP引擎处于不稳定的状态。 如果该错误没有被用户自定义句柄捕获 (参见 set_error_handler() ),将成为一个 E_ERROR 从而脚本会终止运行。 |
8192 | E_DEPRECATED | 运行时通知。启用后将会对在未来版本中可能无法正常工作的代码给出警告。 |
16384 | E_USER_DEPRECATED | 用户产生的警告信息。 类似E_DEPRECATED , 但是是由用户自己在代码中使用PHP函数 trigger_error() 来产生的。 |
30719 | E_ALL | E_STRICT 除外的所有错误和警告信息。PHP5.4后包含E_STRICT 错误 |
PHP错误类型总结
E_ERROR
:运行时致命错误E_WARNING
:运行时警告E_PARSE
:解析时错误E_NOTICE
:运行时通知,可能为错误。E_CODE_ERROR
和E_CODE_WARNING
:PHP初始化时产生的致命错误和警告E_COMPIL_ERROR
和E_COMPIL_WARNING
:编译时产生的致命错误和警告E_STRICT
:你的代码可以运行,但是不是PHP建议的写法。E_DEPRECATED
:运行时通知,启用后将会对在未来版本中可能无法正常工作的代码给出警告。E_RECOVERABLE_ERROR
:可被捕获的E_ERROR
,如果用户未定义set_error_handler()
函数则成为一个E_ERROR
错误E_USER_ERROR
、E_USER_WARNING
、E_USER_NOTICE
和E_USER_DEPRECATED
:用户自定义的错误,使用trigger_error()
抛出。E_ALL
:除了E_STRICT
以外的所有错误信息。PHP5.4后包含E_STRICT
错误
PHP错误类型使用
可以在配置文件或者 error_reporting()
函数中使用用于设置应该报告何种错误,可以使用按位运算符来组合这些值或者屏蔽某些类型的错误。在配置文件中只能使用 |
、&
、^
、~
和!
来进行组合。
PHP错误配置
错误配置内容
error_reporting = E_ALL // 报告错误级别,什么级别的
display_errors = On // 是否把错误展示在输出上,这个输出可能是output(PHP执行的输出流),也可能是stdout(为进程的标准输出)。PHP5.2以后可以设置值为 `stderr`,则可以将错误展示到 stderr输出(即标准错误输出)
display_startup_errors = On // 是否把启动过程的错误信息显示在页面上
log_errors = On // 是否要记录错误日志
log_errors_max_len = 1024 // 错误日志的最大长度
ignore_repeated_errors = Off // 是否忽略重复的错误
ignore_repeated_source = Off // 忽略重复消息时,也忽略消息的来源
report_memleaks = On // 如果这个参数设置为Off,则内存泄露信息不会显示 (在 stdout 或者日志中)。
track_errors = Off // 是否使用全局变量$php_errormsg来记录最后一个错误
html_errors = On // 是否把输出中的函数等信息变为HTML链接
xmlrpc_errors = 0 // 是否使用XML-RPC的错误信息格式记录错误
xmlrpc_error_number = 0 // 用作 XML-RPC faultCode 元素的值。
docref_root = http://manual/en/ // 如果打开了html_errors参数,PHP将会在出错信息上显示超连接,直接链接到一个说明这个错误或者导致这个错误的函数的页面。你可以从http://www.php.net/docs.php下载php手册,并设置docref_root参数,将他指向你本地的手册所在目录。你还必须设置"docref_ext"来指定文件的扩展名
error_prepend_string = "11" //错误信息之前输出的内容。
error_append_string = "22" //错误信息之后输出的内容。
fastcgi.logging = 0 // 是否把php错误抛出到fastcgi中
error_log = /tmp/php_errors.log // php中的错误显示的日志位置
错误配置的一些说明
error_reporting
:配置什么样子的错误能显示,这个是最重要的控制display_errors
:是否展示错误说明,设置为Off则不显示错误的说明信息
错误相关的一些函数
-
error_reporting([ int $level ] )
:可以设置$level
,不设置则输出当前的错误级别// 关闭所有PHP错误报告 error_reporting(0); // Report simple running errors error_reporting(E_ERROR | E_WARNING | E_PARSE); // 报告 E_NOTICE也挺好 (报告未初始化的变量 // 或者捕获变量名的错误拼写) error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE); // 除了 E_NOTICE,报告其他所有错误 error_reporting(E_ALL ^ E_NOTICE); // 报告所有 PHP 错误 (参见 changelog) error_reporting(E_ALL); // 报告所有 PHP 错误 error_reporting(-1);
-
set_error_handler(callable $error_handler [, int $error_types = E_ALL | E_STRICT ])
:设置用户自定义的错误处理函数。- 其中$error_handle为一个回调函数
- $_error_type:如果没有该掩码, 无论 error_reporting 是如何设置的, error_handler 都会在每个错误发生时被调用。
- 以下是不能被用户自定义函数调用的错误级别:E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、 E_COMPILE_WARNING
error_types
里指定的错误类型都会绕过 PHP 标准错误处理程序, 除非回调函数返回了 FALSE- 如果错误发生在脚本执行之前(比如文件上传时),将不会 调用自定义的错误处理程序因为它尚未在那时注册。
-
bool trigger_error ( string $error_msg [, int $error_type = E_USER_NOTICE ] )
:产生一个用户级别的错误
PHP7错误处理机制
PHP 7 改变了大多数错误的报告方式。不同于传统(PHP 5)的错误报告机制,现在大多数错误被作为 Error 异常抛出。
这种 Error 异常可以像 Exception 异常一样被第一个匹配的 try / catch 块所捕获。如果没有匹配的 catch 块,则调用异常处理函数(事先通过 set_exception_handler()
注册)进行处理。 如果尚未注册异常处理函数,则按照传统方式处理:被报告为一个致命错误(Fatal Error)。
Error 类并非继承自 Exception 类,所以不能用 catch (Exception $e) { ... } 来捕获 Error。你可以用 catch (Error $e) { ... },或者通过注册异常处理函数(set_exception_handler()
)来捕获 Error。
PHP异常
PHP的异常和其他语言中的异常一样,使用 try
、catch
、finally
,只不过PHP的异常系统不会自动抛出,需要手动抛出
,导致PHP异常在程序中的作用减半
(异常就是意料之外的事情,根本我们意料不到的,如果用手动抛出,证明已经预先预料到了,那异常的意义就变味了) 。
常用函数
set_exception_handler(callable $exception_handler)
:设置默认的异常处理程序,用于没有用 try/catch 块来捕获的异常。 在 exception_handler 调用后异常会中止。
$exception_handler
回调函数的参数是Exception
类,PHP7以后为Throwable
类,该类可以捕获大多数的错误
总结
在PHP 中将代码自身异常(一般是环境或者语法非法所致)称作错误 Error
,将运行中出现的逻辑错误称为异常 Exception
。
PHP7之前
error
可以通过set_error_handler()
函数处理错误,但是一部分error
类型是无法进行捕获的。Exception
只能通过用户手动 throw
,未通过 try/catch
的会被set_exception_handler()
捕获,如果未定义set_exception_handler()
函数,也未try/catch
的则会产生一个 Fatal error
。那么问题来了,我们都用过框架,但是为什么框架能处理致命错误?可以参考这篇:PHP 优雅的捕获处理错误 -- E_PARSE / E_ERROR
PHP7之后
PHP7 中出现了 Throwable
接口,该接口由 Error
和 Exception
实现,用户不能直接实现 Throwable
接口,而只能通过继承 Exception
来实现接口(这就和Java有点像了,虽然不能像Java那么强大,但是配合着set_exception_handler()
函数可以捕获大部分的错误与异常,但是像一些如内存不足等错误还是像原来一样让程序停止运行)。可以参考 PHP7中的异常与错误处理