如何做好错误处理?(PHP篇)
起因
之前我在封装 PHP 一个类库的时候,如果有遇到错误(例如构造函数传参不合法的话),则直接 die()
,后来发现这种方法很不好,会直接退出程序。
所以我想到给 PHP 上异常捕获的机制了。
错误处理的原则
1、一定要让 PHP 报告错误
2、在开发环境中要显示错误
3、在生产环境中不能显示错误
4、在开发和生产环境中都要记录错误
PHP 错误处理的种类
一、@
尽管我们可以在可能触发错误的函数前加上 @ 抑制符,不让 PHP 触发错误,但这有悖于常规做法,不建议这么做。
二、die()
因为 die()
= exit()
,遇到错误直接退出,很不友好。
但是早期的一些 PHP 框架和类库还在使用这种方法,例如 codeigniter
。
三、Error
(1) 实例:
//错误处理函数
function MyError($level, $message, $file = '', $line = 0, $context = [])
{
//todo...
}
//设置错误处理函数
set_error_handler("MyError", E_ALL & ~E_NOTICE); //排除了 E_NOTICE,拦截没有必要的错误提示
// 触发错误
$test=2;
if ($test>1)
{
trigger_error("变量值必须小于等于 1",E_USER_WARNING);
}
//恢复错误处理设置(可选)
//restore_error_handler()
(2) 错误处理函数
的参数(对应例子中的 MyError()
)
参数 | 描述 |
---|---|
error_level | 必需。为用户定义的错误规定错误报告级别。必须是一个数字。参见下面的表格:错误报告级别。 |
error_message | 必需。为用户定义的错误规定错误消息。 |
error_file | 可选。规定错误发生的文件名。 |
error_line | 可选。规定错误发生的行号。 |
error_context | 可选。规定一个数组,包含了当错误发生时在用的每个变量以及它们的值。 |
(3) error_level (错误报告的级别)
| 值 | 常量 |描述 |
| :------------: |:-------------😐
| 2 | E_WARNING | 非致命的 run-time 错误。不暂停脚本执行。 |
| 8 | E_NOTICE | run-time 通知。在脚本发现可能有错误时发生,但也可能在脚本正常运行时发生。 |
| 256 | E_USER_ERROR | 致命的用户生成的错误。这类似于程序员使用 PHP 函数 trigger_error() 设置的 E_ERROR。 |
| 512 | E_USER_WARNING | 非致命的用户生成的警告。这类似于程序员使用 PHP 函数 trigger_error() 设置的 E_WARNING。 |
| 1024 | E_USER_NOTIC | 用户生成的通知。这类似于程序员使用 PHP 函数 trigger_error() 设置的 E_NOTICE。 |
| 4096 | E_RECOVERABLE_ERROR | 可捕获的致命错误。类似 E_ERROR,但可被用户定义的处理程序捕获。(参见 set_error_handler()) |
| 8191 | E_ALL | 所有错误和警告。(在 PHP 5.4 中,E_STRICT 成为 E_ALL 的一部分) |
四、Exception
早期的 PHP 只有错误没有异常。
现在的一些 PHP 框架和类库已经离不开异常了,例如laravel
。
(1)Exception 对象
参数: Code
+ Message
$exception = new Exception('Danger, Will Robinson!', 100);
$code = $exception->getCode();
$message = $exception->getMessage();
(2) 实例
ini_set('display_errors', 'Off'); // 隐藏所有错误的显示
error_reporting(E_ALL & ~E_NOTICE); //将会向 PHP 报告发生的每个错误,除了 E_NOTICE
ini_set("log_errors", 'On'); //开启错误日志
ini_set('error_log', dirname(__FILE__) . '/../php_errors.log'); //指定产生的错误报告写入的日志文件位置
// ********** 异常 **********
//自定义 Exception
class CustomException extends Exception
{
public function errorMessage()
{
// 自定义错误信息
$errorMsg = '错误行号 '.$this->getLine().' in '.$this->getFile()
.': <b>'.$this->getMessage().'</b>';
return $errorMsg;
}
}
//设置顶层异常处理器
set_exception_handler(function (Exception $e) {
$exception_name = get_class($e);
if ($exception_name === "InvalidArgumentException") { //PHP 内置 Exception
//todo...
} else if ($exception_name === "CustomException") { //自定义 Exception
//todo...
} else {
//todo...
}
});
//触发异常
throw new MyException('x','xxx');
throw new Exception('Uncaught Exception occurred');
//还原成之前的全局异常处理程序
//restore_exception_handler();
(3) PHP 内置的 Exception 对象
参数 | 描述 |
---|---|
Error | |
ArithmeticError | 计算错误 |
DivisionByZeroError | 不可以除以0的错误 |
AssertionError | 断言错误 |
ParseError | parse错误 |
TypeError | 类型错误 |
ArgumentCountError | 参数数量错误 |
Exception | |
ClosedGeneratorException | 当生成器的值已经用完时,请求新的值将触发此异常。 |
DOMException | |
ErrorException | |
IntlException | Internationalization(国际化)错误 |
LogicException | 逻辑错误 |
BadFunctionCallException | 如果回调引用未定义的函数或缺少某些参数,则抛出异常。 |
BadMethodCallException | 当一个回调方法是一个未定义的方法或缺失一些参数时会抛出该异常。 |
DomainException | 如果值不符合已定义的有效数据域,则抛出异常。 |
InvalidArgumentException | 无效参数错误 |
LengthException | 长度错误 |
OutOfRangeException | 越界错误 |
PharException | Phar类错误 |
ReflectionException | |
RuntimeException | 如果只能在运行时发现错误,则抛出异常。 |
OutOfBoundsException | 如果值不是有效的键,则抛出异常。 |
OverflowException | 溢出错误 |
UnderflowException | 下溢错误。在空容器上执行无效操作(例如移除元素)时抛出异常。 |
PDOException | POD类错误 |
RangeException | 范围错误 |
UnexpectedValueException | 不期望的参数值错误 |
SodiumException | Sodium类错误 |

总结:
错误
和 异常
的区别:
(1) 触发方式不同
Error
trigger_error(错误级别)
Exception
throw(new xxxException)
(2) 目的不同
error 单纯是报错,而 exception 的目的是为了被捕获,从而补救错误。
对于高版本 PHP 我们基本上只需要处理异常,不用管错误,或者用全局接管错误,然后再抛为异常。
(3) PHP 错误机制图解

参考资料
[1] http://www.cnblogs.com/yjf512/p/5314345.html(PHP 的错误机制总结)
[2] https://juejin.im/entry/5987d2ff6fb9a03c314fe732(PHP 的错误和异常处理机制)
[3] http://laravelacademy.org/post/7500.html (最佳实践系列(十一):深入探讨 PHP 错误异常处理机制及 Laravel 框架底层的相应实现)
[4] http://php.net/manual/en/class.error.php (PHP Manual Language Reference Predefined Exceptions)
[5] http://www.runoob.com/php/php-exception.html (PHP 异常处理)
[6] http://www.runoob.com/php/php-error.html (PHP 错误处理)