上手并过渡到PHP7(4)——取代fatal error的engine exceptions
上手并过渡到PHP7
取代fatal error的engine exceptions
自从PHP 4以来,PHP的错误处理几乎就是一成不变的。只不过在PHP 5.0里添加了E_STRICT,在PHP 5.2里添加了E_RECOVERABLE_ERROR,在PHP 5.3里,添加了E_DPRECATED这几种Error level。尽管PHP 5中加入了Exception,但PHP中只有很少的模块使用了这个机制(例如:pdo和spl)。在PHP 7中,这个尴尬的现状,终于被彻底改变了。
Engine Exceptions
PHP 7里,几乎所有的Fatal和Catchable fatal error都被替换成了 Engine exceptions 。但是,所有未被catch的异常仍旧会导致一个“传统”的PHP fatal error,因此,对于各种fatal error来说,这个改动几乎是向前兼容的。但对于其他类型的Error(non-fatal)来说,由于它们也被转换成了异常,忽略它们同样会导致一个fatal error,因此,对这些错误的处理,并不向前兼容。
把各种错误统一成异常的一个好处,就是我们可以使用try...catch来统一处理它们,进而,为错误现场的正确清理提供诸多保障:
确保finally内的代码被调用;
确保类的__destruct()函数被调用;
使用register_shutdown_function()注册的回调函数被调用;
总之,因为有了engine exceptions,错误更不容易被忽略,也更容易被处理。我们来看一个例子: 构造函数中发生异常会怎么样呢?
getMessage();
}
在PHP 5里,$msg会是一个null或不可用对象。在PHP 7里,MessageFormatter则会抛出一个\IntlException异常:Constructor failed。
PHP 7 Exception架构
为了能够和PHP 5兼容,我们必须确保之前的call-all写法:
getMessage();
}
不能捕获新的PHP 7 engine exceptions(因为在PHP 7之前,Fatal error是不能够被捕获和处理的)。这样,那些没有被处理的异常,才会像之前一样导致一个Fatal error。因此,所有新的engine exception并没有继承之前的\Exception类,而是继承了一个新的叫做\Error的基类。
class Error implements Throwable {
/* Inherited methods */
abstract public string Throwable::getMessage ( void )
abstract public int Throwable::getCode ( void )
...
}
基于\Error exception,派生了5个新的engine exception:ArithmeticError / AssertionError / DivisionByZeroError / ParseError / TypeError。在PHP 7里,无论是老的\Exception还是新的\Error,它们都实现了一个共同的interface: \Throwable。因此,\Throwable是PHP 7异常架构里最顶层的接口。所以,如果你想在PHP 7里实现一个catch-all,你可以这样:
getMessage();
}
Error exception
接下来,我们来分别了解一下新增的这几个engine exception:
\Error
这个异常代表了PHP 7中标准的fatal和catchable-fatal错误,如果它不被catch,就会进而触发一个“传统”的PHP fatal error。例如,我们调用一个不存在的方法:
try {
nonExistFunc();
}
catch(\Error $e) {
echo "\Error catch: ".$e->getMessage();
}
\AssertionError
如果你在php.ini里,把assert.exception设置成1,当断言失败的时候,你就会收到这个异常:
try {
assert('1 > 2', '1 > 2, are your serious?');
}
catch(\AssertionError $e) {
echo $e->getMessage();
}
“如果我们在assert()里不设置错误信息,\AssertError读不到错误信息的。”
最佳实践
\ArithmeticError and \DivisionByZeroError
\ArithmeticError和算数运算有关。运算发生越界或者bit shift负数位数,都会导致发生\ArithmeticError。例如下面这段代码就会导致“Bit shift by negative number”错误。
try {
1 >> -1;
}
catch(\ArithmeticError $e) {
echo $e->getMessage();
}
而\DivisionByZeroError则表示除数为0而导致的错误(无论我们使用 / % 或 intdiv(),只要除数为0,都会导致这个错误)。
\TypeError
我们在前面的视频介绍过PHP 7的scalar type hints以及strict mode。无论是scalar type hints还是传统的type hints(class / interface / callable / array),只要类型不匹配type hints约束的时候,就会导致\TypeErro异常。
try {
1 >> -1;
}
catch(\ArithmeticError $e) {
echo $e->getMessage();
}
set_error_handler()
在PHP 7里,有一点是和PHP 5不兼容的,如果我们之前使用set_error_handler()处理catchable fatal error,在PHP 7里,这些error已经变成了engine exception,它们不会再被set_error_handler()处理。
自定义异常
尽管\Throwable是PHP 7中的顶层异常接口,但当我们自定义异常的时候,却不能直接实现它。否则PHP会提示我们下面的错误:
class MyException implements \Throwable {}
Fatal error: Class MyException cannot implement interface Throwable, extend Exception or Error instead
为了能正确处理异常行号、文件名和stack trace,我们只能从\Exception或者\Error派生自己的异常类。但是,我们可以拓展新的\Throwable接口,并且实现其中的方法:
interface MyExceptionInterface extends \Throwable { }
class MyError
extends \Error implements MyExceptionInterface { }
上手并过渡到PHP7(4)——取代fatal error的engine exceptions的更多相关文章
- 上手并过渡到PHP7(1)——基于Homestead的PHP7和XDdebug环境
PHP7 up and running 泊学实操视频泊学原文链接PHP7, Xdebug and Homestead 在经历了13个RC版本之后,PHP 7终于来了.在我们上手评估PHP 7的新特性之 ...
- 上手并过渡到PHP7(3)——Uniform Variable Syntax到底统一了什么
PHP7 up and running 泊学原文链接泊学实操视频 Uniform Variable Syntax 在PHP 7提出Uniform Variable Syntax之前,我们大多数人可能都 ...
- 上手并过渡到PHP7(5)——轻量级“集合”迭代器-Generator
轻量级“集合”迭代器-Generator泊学视频链接泊阅文档链接Generator是PHP 5.5加入的新语言特性.但是,它似乎并没有被很多PHP开发者广泛采用.因此,在我们了解PHP 7对Gener ...
- 上手并过渡到PHP7(2)——必须传递int, string, bool参数?没问题
Type hints, Type safe 泊学实操视频 泊学原文链接PHP 7中最引人注目的新特性之一,无疑是Scalar type hints.我们可以在函数参数和返回值中使用scalar typ ...
- VS2010遇到fatal error C1083: 无法打开预编译头文件:“xxx.pch”: No such file or directory
对C++和VS2010非常不熟悉,但是无奈赶着项目,只能看了点基础就上手,然后就碰到这个问题了. 原因分析: http://bbs.csdn.net/topics/340191697?page=1 编 ...
- PHP Fatal error: Call to undefined function mysql_connect() 错误解释
我使用的是5.6.11版本的php 刚开始以为编译参数加了--with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd,就可以不能安装mysql了. 但是使用了mysq ...
- PHP Fatal error: Uncaught Error: Call to undefined function pcntl_fork().. 开启php pcntl扩展实现多进程
在使用函数pcntl_fork()时报错 Fatal error: Uncaught Error: Call to undefined function pcntl_fork()....,原因是没有 ...
- php捕获Fatal error错误与异常处理
php中的错误和异常是两个不同的概念. 错误:是因为脚本的问题,比如少写了分号,调用未定义的函数,除0,等一些编译语法错误. 异常:是因为业务逻辑和流程,不符合预期情况,比如验证请求参数,不通过就用 ...
- fatal error C1045: 编译器限制 : 链接规范嵌套太深
前言 我相信你是遇到了同样的问题.通过搜索引擎来到这里的.为了不耽误排查问题的时间,我提前说明一下这篇文章所描述的问题范畴: 我遇到的问题和 c++ 模板相关: 如果我减少传递的参数的话,是有可能避免 ...
随机推荐
- oc 类型判断
#import <UIKit/UIKit.h> #import "AppDelegate.h" @interface A : NSObject @end @implem ...
- oc字符串的用法
#import <UIKit/UIKit.h> #import "AppDelegate.h" int main(int argc, char * argv[]) { ...
- PMP_PMP考试须知
考试报名 按照报名须知和填表指南中的要求提交报名材料同时交纳考试费用.北京地区的考生直接到国家外国专家局培训中心报名:外地考生到所在地报名点报名:未设有报名点的地区,可直接与国家外国专家局培训中心联系 ...
- 文件描述符file descriptor与inode的相关知识
每个进程在Linux内核中都有一个task_struct结构体来维护进程相关的 信息,称为进程描述符(Process Descriptor),而在操作系统理论中称为进程控制块 (PCB,Process ...
- STM32 mdk软件仿真时过不去时钟的问题
stm32的程序用MDK软件仿真时,由于系统时钟初始化函数里有个等待系统时钟准备好的循环,所以过不去. 设置方式如下:这么设置之后仿真时就可以直接进入main函数了.
- Ruby gem 更换国内源
gem sources --add http://gems.ruby-china.org/ --remove https://rubygems.org/
- Logstash怎么导入csv
Logstash.Conf input { file { type => "SSRCode" path => "E:/FTPRootWorkSpace/SD/ ...
- php读取sqlite数据库入门实例
php读取sqlite数据库的例子,php编程中操作sqlite入门实例.原文参考:http://www.jbxue.com/article/php/22383.html在使用SQLite前,要确保p ...
- android framework-下载Android系统源代码
□ apt-get install git-core curl #先下载这两个工具 □ mkdir android-froyo #建立下载目录 □ cd android-froyo #进入下载目录 □ ...
- 手动方式SQL注入脚本命令之精华版
.判断是否有注入;and = ;and = .初步判断是否是mssql ;and user> .注入参数是字符and [查询条件] and = .搜索时没过滤参数的and [查询条件] and ...