PHP 7 错误异常级别

30人阅读 评论(0) 收藏 举报
分类:

PHP 7 错误异常级别

探究 PHP 7 的异常层次结构

在过去的 PHP 中,几乎不可能会去处理致命错误。致命错误只会轻易的终止脚本执行,而不会调用 set_error_hander() 错误处理程序。

在 PHP 7 中,当致命或是可恢复性错误 (E_ERROR and E_RECOVERABLE_ERROR) 发生时,异常会被捕获,而不是中止脚本。在特定的情况下,还是存在会致命的错误,比如内存不足之类,也会像之前一样立即中止脚本。PHP 7 中未捕获的异常依旧时致命错误。这意味着,如果 PHP 5.x 中未捕获的异常,在 PHP 7 中依旧是致命错误。

注意,例如警告或是通知错误在 PHP 7 中保持不变,只有致命错误或是可恢复性错误会抛出异常。

致命或是可恢复性错误的抛出并不延伸自 Exception 类。这种分离是为了防止现存的 PHP 5.x 代码接收到的错误异常调用到终止程序。致命或是可恢复错误抛出的异常将实例化一个新的异常类:Error。和其他异常类相同,被捕获到的 Error 类将会在最后一个程序块执行完毕之后再行处理。

相较于 PHP 7 alpha-2 之前,PHP 7 的异常类层次有所不同, 被抛出的致命和可恢复性的错误将于 EngineException 类实例化,而 EnginException 类并不继承于 Exception。Exception 和 EngineException 都继承于 BaseException。

Throwable

为了联合这两个异常分支,Exception 和 Error 都实现了一个新的接口,Throwable。

PHP 7 中新的异常层次如下:

Throwable //(接口)
    |- Exception implements Throwable
        |- ...
    |- Error implements Throwable
        |- TypeError extends Error 
        |- ParseError extends Error // 编译时错误
        |- ArithmeticError extends Error
            |- DivisionByZeroError extends ArithmeticError
        |- AssertionError extends Error

如果在 PHP 7 中定义 Throwable 接口,那应该和下面的代码相近。

interface Throwable
{
    public function getMessage(): string;
    public function getCode(): int;
    public function getFile(): string;
    public function getLine(): int;
    public function getTrace(): array;
    public function getTraceAsString(): string;
    public function getPrevious(): Throwable;
    public function __toString(): string;
}

这个接口应当很熟悉。Throwable 特定的方法和 Exception 的相同。唯一不同的是 Throwable::getPrevious() 会返回 Throwable Exception 和 Error 类的构造函数都将接收一个 Throwable 的实例作为先前的异常。

Throwable 可以在 try/catch 块中用老捕获异常或是错误对象(将来可能可以捕获更多的异常类型)。记住,这里更建议捕获更为具体的异常类,并采取相应的处理措施。然而,在一些场合下,需要宽泛的捕获异常(比如日志或是框架的错误处理)。在 PHP 7 中,这些异常捕获块更适合使用 Throwable 而不是 Exception。

try {
    // Code that may throw an Exception or Error.
} catch (Throwable $t) {
    // Handle exception
}

自定义类不能实现 Throwable 插件,这个部分由于可预见性和一致性:只有实例化 Excetion 和 Error 类才能抛出异常。此外,异常携带了栈中被创建的对象的信息。自定义类并未自动拥有保存信息的参数。

Throwable can be extended to create package-specific interfaces or add additional methods. 只有继承了 Exception 或是 Error 的类才可以实现拓展了 Throwable 的插件。

interface MyPackageThrowable extends Throwable {}

class MyPackageException extends Exception implements MyPackageThrowable {}

throw new MyPackageException();

Error

在 PHP 5.下版本中所有的 errors 都是致命错误或是可恢复性致命错误,而在 PHP 7 中都抛出 Error 的实例化。像其他异常 Error 对象可以通过 try/catch 程序块捕获。

$var = 1;

try {
    $var->method(); // Throws an Error object in PHP 7.
} catch (Error $e) {
    // Handle error
}

通常,之前的致命错误都将抛出 Error 基类的实例化,但是一些错误会抛出更加确切的 Error 子类:TypeError, ParseError, and AssertionError。

TypeError (类型错误)

TypeError 实例化的抛出是由实参和形参 当调用函数时申明的形参和实参类型不一致(传入参数和方法中定义的参数类型不一致)将会抛出一个 TypeError 实例。

function add(int $left, int $right)
{
    return $left + $right;
}

try {
    $value = add('left', 'right');
} catch (TypeError $e) {
    echo $e->getMessage(), "\n";
}

得到的输出:

Argument 1 passed to add() must be of the type integer, string given

ParseError (解析错误)

included/required 文件,或者 eval() 中的代码包含语法错误时,ParseError 将会被抛出。

try {
    require 'file-with-parse-error.php';
} catch (ParseError $e) {
    echo $e->getMessage(), "\n";
}

ArithmeticError (算数错误)

抛出 ArithmeticError 错误有两种情况:负数位移,或者使用 PHP_INT_MIN 当作分子,-1 做分母调用 intdiv()(PHP_INI_MIN / -1 返回值是浮点型)。

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

DivisionByZeroError (分母为零)

分母为零时使用 intdiv() 或者取余(%) 会抛出 DivisionByZeroError 错误。注意,除零只会引起一个警告,计算结果为 NaN。

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

AssertionError (断言)

当不满足 assert() 设定的条件时,将会抛出一个 AssertionError 错误。

ini_set('zend.assertions', 1);
ini_set('assert.exception', 1);

$test = 1;

assert($test === 0);

不满足 assert() 设定的条件,抛出一个 AssertionError 错误,并且 assert.exception = 1,异常输出如下:

Fatal error: Uncaught AssertionError: assert($test === 0)

assert() is only executed and will only throw an AssertionError if assertions are enabled and set to throw exceptions with ini settings zend.assertions = 1 and assert.exception = 1.

使用 Error

用户可以创建自己的 Error 类,作为 Error 基类的拓展。这可能带来重要的问题:什么场合下应该抛出一个 Exception 类的子类实例,什么场合下又应该抛出 Error 类的子类实例?

由于错误对象不应当在程序运行中处理,捕获错误对象应当是少见的。通常而言,错误对象应当捕获并记录之,执行必要的清理,并给用户展示错误信息。

编写兼容 PHP 5.x 和 7 Exceptions 类的代码

在 PHP 5.x 和 7 使用相同的代码捕获异常,可以实用多重捕获代码块,首先捕获 Throwable,之后时 Exception。一旦不需要维护 PHP 5.x 的系统,代码块可以立刻被清理掉。

try {
    // Code that may throw an Exception or Error.
} catch (Throwable $t) {
    // Executed only in PHP 7, will not match in PHP 5.x
} catch (Exception $e) {
    // Executed only in PHP 5.x, will not be reached in PHP 7
}

英文原文: trowski.com/2015

本文虽拙,却也系作者劳动,转载还请保留本文链接: http://cyleft.com/?p=721

查看评论

Java-XML数据绑定工具大比拼

把Java对象映射成XML文档,这是Java对象持久化的一种新思路。在XML.com的一篇文章里,作者对四种主要的Java-XML映射工具进行了全面的比较:Breeze XML Binder, a t...
  • gigix
  • gigix
  • 2003-09-09 09:13:00
  • 2297

在php中调用接口以及编写接口

如:http://localhost/openUser.php?act=get_user_list&amp;amp;type=json在这里openUser.php相当于一个接口,其中get_user...
  • sunshao904
  • sunshao904
  • 2018-04-09 16:54:48
  • 35

php7的一些变化

1. php7的变化: 1)抽象语法树 之前的php版本、php代码在语法解析阶段直接生成了zendvm指令、也就是在zend_language_parser.y中直接生成opline指...
  • njys1
  • njys1
  • 2018-04-07 13:58:58
  • 36

Linux 6 下编译安装 PHP 5.6

PHP(外文名:PHP: Hypertext Preprocessor,中文名:“超文本预处理器”)是一种通用开源脚本语言。语法吸收了C语言、Java和Perl的特点,利于学习,使用广泛,主要适用于W...
  • robinson_0612
  • robinson_0612
  • 2016-07-15 11:26:32
  • 7863

PHP开发API接口注意事项

1、单文件实现多接口的形式有很多种,例如:if..elseif.. 或 switch 或 动态方法 (也就是TP的这种访问函数体的形式) 2、对于数据的输出最好用json,json具有相当强大的跨平...
  • qq_26291823
  • qq_26291823
  • 2016-11-25 17:18:15
  • 4007

windows下Redis+PHP使用

环境:Windows7 x64 Apache2.4 PHP5.6 mysql5.5 原料:redis插件和redis服务器软件 下载地址:redis插件http://windows.php.n...
  • u013285896
  • u013285896
  • 2016-05-26 23:55:51
  • 3087

PHP 基础知识小结

PHP 基础知识总结PHP 代表 PHP: Hypertext PreprocessorPHP 文件可包含文本、HTML、JavaScript代码和 PHP 代码PHP 代码在服务器上执行,结果以纯 ...
  • silvercell
  • silvercell
  • 2018-04-06 09:09:38
  • 106

Windows PHP 开启opcache的方法

PHP opcache可以提升性能.Windows PHP 配置 opcache 的方法如下: 1、先检查PHP目录下ext目录中有没有php_opcache.dll,没有的话自己下载(PHP ...
  • weixin_38336238
  • weixin_38336238
  • 2017-06-06 14:24:35
  • 1381

CentOS6.5安装指定的PHP版本(php5.5)

安装指定的php版本 参考:https://webtatic.com/packages/php55/ 查询是否安装有php #rpm -qa|grep php 删除之前安装的php版本 (yum ...
  • leejianjun
  • leejianjun
  • 2016-08-13 18:47:45
  • 9182

php+mysql实现分页:上一页,下一页

mysql里将数据分页显示的语句是:limit  5,1。5表示检索开始位置,1表示显示1页 所以在php中要实现上一页,下一页就要传一个数据page给limit,就可以分页。 可以理解为三个步骤: ...
  • yuanqishaonv
  • yuanqishaonv
  • 2016-09-23 13:31:07
  • 14558
    个人资料
    等级:
    访问量: 229
    积分: 63
    排名: 162万+
    文章分类
    文章存档