PHP 异常和错误处理:错误处理机制 Draft 3 个改进

处理原则

如果没有做任何配置,PHP 的错误是会直接打印出来的。古老的 PHP 应用也确实有这么做的,但现代应用显然不能这样,现代应用的错误应该遵循以下规则:

一定要让 PHP 报告错误;

在开发环境中要显示错误;

在生产环境中不能显示错误;

在开发和生产环境中都要记录错误。

生产环境下的处理机制

在生产环境下,错误不能直接打印出来,应该记到 log 文件中,并返回给用户一个笼统的错误信息。set_error_handler 函数 就是设置用户自定义的错误处理函数,以处理脚本中出现的错误。我们可以在这个函数中将错误信息打到 log 文件中,并统一返回错误信息。

本来这个函数是搭配 trigger_error 函数 使用的。用户通过 trigger_error 产生 error,然后用 error_handler 来处理错误。只是在这种场景下往往「异常」更好用,所以这么用的并不多。

值得注意的点

  1. 错误级别 所述的 16 种错误中,有一部分相当重要的错误并不能被 error_handler 捕获:

    以下级别的错误不能由用户定义的函数来处理: E_ERROR、 E_PARSE、 E_CORE_ERROR、 E_CORE_WARNING、 E_COMPILE_ERROR、E_COMPILE_WARNING,和在调用 set_error_handler() 函数所在文件中产生的大多数 E_STRICT。

  2. error_handler 处理完毕,脚本将会继续执行发生错误的后一行。在某些情况下,你可能希望遇到某些错误可以中断脚本的执行。
    也就是说,我们处理完 E_WARNING 之后,需要及时退出脚本( 通过 die() 或 exit())。

PHP7 的错误

PHP 7 改变了大多数错误的报告方式。不同于传统(PHP 5)的错误报告机制,现在大多数错误被作为 Error 异常抛出(在 PHP7 中,只有 fatal error 和 recoverable error 抛出异常,其他 error 比如 warning 和 notice 的表现不变)。PHP7 中的 Error 和 Exception 的关系如下:

interface Throwable
    |- Exception implements Throwable
        |- ...
    |- Error implements Throwable
        |- TypeError extends Error
        |- ParseError extends Error
        |- ArithmeticError extends Error
            |- DivisionByZeroError extends ArithmeticError
        |- AssertionError extends Error

值得注意的是,Error 类表现上和 Exception 基本一致,可以像异常 Exception 一样被第一个匹配的 try / catch块所捕获,如果没有匹配的 catch块,则调用异常处理函数(事先通过 set_exception_handler() 注册)进行处理。

如果尚未注册异常处理函数,则按照传统方式处理,被报告为一个致命错误(Fatal Error)。但并非继承自 Exception 类(要考虑到和 PHP5 的兼容性),所以不能用 catch (Exception $e) { ... }来捕获,而需要使用 catch (Error $e) { ... },当然,也可以使用 set_exception_handler 来捕获。

但是,用户不能自己定义类实现 Throwable,这是为了保证只有 ExceptionError 才可以抛出。

PHP7 的 ERROR 处理

PHP7 中的 fatal error 会抛出 Error,且可以被正常 catch 到:

<?php
$a = 1;
try {
  $a->nonexist();
} catch (Error $e) {
  // Handle error
}

也有些错误场景下会抛出更加详细的错误,比如:

<?php
// TypeError
function test(int $i) {
  echo $i;
}
try {
  test('test');
} catch (TypeError $e) {
  // Handle error
}

// ParseError
try{
  eval('i=1;');
} catch (ParseError $e) { 
  echo $e->getMessage(), "\n";
}

// ArithmeticError
try {
    $value = 1 << -1;
} catch (ArithmeticError $e) {
    echo $e->getMessage(), "\n";
}

// DivisionByZeroError
try {
    $value = 1 % 0;
} catch (DivisionByZeroError $e) {
    echo $e->getMessage(), "\n";
}

结语

PHP 7 完善了 PHP 5 鸡肋的错误处理机制,可以说是一个很大的进步。

本 Wiki 尚未完善,邀您参与 如何撰写一篇高品质的 Wiki?
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!