PHP 中的 Exception, Error, ThrowablePHP 中将代码自身非常(一样平常是环境或者语法造孽所致)称作缺点 Error,将运行中涌现的逻辑缺点称为非常 Exception缺点是没法通过代码处理的,而非常则可以通过 try/catch 来处理PHP7 中涌现了 Throwable 接口,该接口由 Error 和 Exception 实现,用户不能直接实现 Throwable 接口,而只能通过继续 Exception 来实现接口PHP7 非常处理机制
过去的 PHP,处理致命缺点险些是不可能的。致命缺点不会调用由 set_error_handler() 设置的处理办法,而是大略的停滞脚本的实行。
在 PHP7 中,当致命缺点和可捕获的缺点(E_ERROR 和 E_RECOVERABLE_ERROR)发生时会抛出非常,而不是直接停滞脚本的运行。对付某些情形,比如内存溢出,致命缺点则仍旧像之前一样直接停滞脚本实行。在 PHP7 中,一个未捕获的非常也会是一个致命缺点。这意味着在 PHP5.x 中致命缺点抛出的非常未捕获,在 PHP7 中也是致命缺点。
把稳:其他级别的缺点如 warning 和 notice,和之前一样不会抛出非常,只有 fatal 和 recoverable 级别的缺点会抛出非常。
从 fatal 和 recoverable 级别缺点抛出的非常并非继续自 Exception 类。这种分离是为了防止现有 PHP5.x 的用于停滞脚本运行的代码也捕获到缺点抛出的非常。fatal 和 recoverable 级别的缺点抛出的非常是一个全新分离出来的类 Error 类的实例。跟其他非常一样,Error 类非常也能被捕获和处理,同样许可在 finally 之类的块构造中运行。
Throwable为了统一两个非常分支,Exception 和 Error 都实现了一个全新的接口:Throwable
PHP7 中新的非常构造如下:
interface Throwable |- Exception implements Throwable |- ... |- Error implements Throwable |- TypeError extends Error |- ParseError extends Error |- ArithmeticError extends Error |- DivisionByZeroError extends ArithmeticError |- AssertionError extends Error
如果在 PHP7 的代码中定义了 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 的。Exception 和 Error 的布局函数跟之前 Exception 一样,可以接管任何 Throwable 的实例。
Throwable 可以用于 try/catch块中捕获 Exception 和 Error 工具(或是任何未来可能的非常类型)。记住捕获更多特定类型的非常并且对之做相应的处理是更好的实践。然而在某种情形下我们想捕获任何类型的非常(比如日志或框架中缺点处理)。在 PHP7 中,要捕获所有的该当利用 Throwable 而不是 Exception。
try { // Code that may throw an Exception or Error.} catch (Throwable $t) { // Handle exception}
用户定义的类不能实现 Throwable 接口。做出这个决定一定程度上是为了预测性和同等性——只有 Exception 和 Error 的工具可以被抛出。此外,非常须要携带工具在追溯堆栈中创建位置的信息,而用户定义的工具不会自动的有参数来存储这些信息。
Throwable 可以被继续从而创建特定的包接口或者添加额外的方法。一个继续自 Throwable 的接口只能被 Exception 或 Error 的子类来实现。
interface MyPackageThrowable extends Throwable {}class MyPackageException extends Exception implements MyPackageThrowable {}throw new MyPackageException();
Error
事实上,PHP5.x 中所有的缺点都是 fatal 或 recoverable 级别的缺点,在 PHP7 中都能抛出一个 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 以及 AssertionError。
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
当 include/require 文件或 eval() 代码存在语法缺点时,ParseError 会被抛出。
try { require 'file-with-parse-error.php';} catch (ParseError $e) { echo $e->getMessage(), "\n";}
ArithmeticError
ArithmeticError 在两种情形下会被抛出。一是位移操作负数位。二是调用intdiv() 时分子是 PHP_INT_MIN 且分母是 -1 (这个利用除法运算符的表达式:PHP_INT_MIN / -1,结果是浮点型)。
try { $value = 1 << -1;} catch (ArithmeticError $e) { echo $e->getMessage();//Bit shift by negative number}
DevisionByZeroError
当 intdiv() 的分母是 0 或者取模操作 (%) 等分母是 0 时,DivisionByZeroError 会被抛出。把稳在除法运算符 (/) 中利用 0 作除数(也即xxx/0这样写)时只会触发一个 warning,这时候若分子非零结果是 INF,若分子是 0 结果是 NaN。
try { $value = 1 % 0;} catch (DivisionByZeroError $e) { echo $e->getMessage();//Modulo by zero}
AssertionError
当 assert() 的条件不知足时,AssertionError 会被抛出。
ini_set('zend.assertions', 1);ini_set('assert.exception', 1);$test = 1;assert($test === 0);//Fatal error: Uncaught AssertionError: assert($test === 0)
只有断言启用并且 zend.assertions = 1 和 assert.exception = 1 时,assert()才会实行并抛 AssertionError。
在你的代码中利用 Error用户可以通过继续 Error 来创建符合自己
层级哀求的 Error 类。这就形成了一个问题:什么情形下该当抛出 Exception,什么情形下该当抛出 Error。
Error 该当用来表示须要程序员关注的代码问题。从 PHP 引擎抛出的 Error 工具属于这些分类,常日都是代码级别的缺点,比如通报了缺点类型的参数给一个函数或者解析一个文件发生缺点。Exception 则该当用于在运行时能安全的处理,并且另一个动作能连续实行的情形。
由于 Error 工具不应该在运行时被处理,因此捕获 Error 工具也该当是不频繁的。一样平常来说,Error 工具仅被捕获用于日志记录、实行必要的清理以及展示缺点信息给用户。
编写代码支持 PHP5.x 和 PHP7 的非常为了在同样的代码中捕获任何 PHP5.x 和 PHP7 的非常,可以利用多个 catch,先捕获 Throwable,然后是 Exception。当 PHP5.x 不再须要支持时,捕获 Exception 的 catch 块可以移除。
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}
不幸的是,处理非常的函数中的类型声明不随意马虎确定。当 Exception 用于函数参数类型声明时,如果函数调用时候能用 Error 的实例,这个类型声明就要去掉。当 PHP5.x 不须要被支持时,类型声明则可以还原为 Throwable。
给你代码往期回顾:
给你代码:leetcode随笔
给你代码:小程序页面间订阅及触发事理的实现
暴走状态!
小程序用户UnionID的获取及登录状态掩护——给你代码