上手并过渡到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++ 模板相关: 如果我减少传递的参数的话,是有可能避免 ...
随机推荐
- MVC笔记 Controller相关技术
一.Controller的责任 MVC的核心就是Controller(控制器),它负责处理浏览器传送过来的所有请求,并决定要将什么内容响应给浏览器.但Controller并不负责决定内容应该如何显示, ...
- VS报:"dll标记为系统必备组件,必须对其进行强签名"错误
问题: VS生成程序时,报“要将程序集“XX.dll”标记为系统必备组件,必须对其进行强签名.”错误. 解决方法: 1)在报错的解决方案中找到一个可以发布的项目(引用该XX.dll的项目未必可以发布) ...
- 怎样让VMware上的虚拟机ping通外网(图解教程)
近期在实习项目中遇到一个问题. 因測试须要,本人在win7上安装VMWare后在启动两台ubuntuserver.两台主机的网络配置所有採用NAT方式实现连接. 之后一路畅通.主机ping通虚拟机和外 ...
- Python min() 方法
描述 Python min() 方法返回字符串中最小的字母(26个字母中最小的是A). 语法 min() 方法语法: min(S) 参数 S -- 字符串. 返回值 返回字符串中最小的字母. 实例 以 ...
- Python fabs() 函数
描述 fabs() 方法返回数字的绝对值,如math.fabs(-10) 返回10.0. fabs() 函数类似于 abs() 函数,但是他有两点区别: abs() 是内置函数. fabs() 函数在 ...
- Comet入门及最简单的Java Demo
在浏览网页的时候,假设有新的消息,怎样接收到?HTTP协议不能由server主动给client发送消息. 1.刷微博.逛论坛贴吧,想看最新的信息怎么办?F5刷新一下就OK了! 2.上面一种方式是被动的 ...
- 怎么样快速完整备份和压缩 很大的 sqlserver 1TB 数据库 -摘自网络
How to increase SQL Database Full Backup speed using compression and Solid State Disks The SQL 2008 ...
- Spring RestTemplate使用教程
简介 Spring'scentral class for synchronous client-side HTTP access.It simplifies communication with HT ...
- kafka工作原理简介
消息队列 消息队列技术是分布式应用间交换信息的一种技术.消息队列可驻留在内存或磁盘上, 队列存储消息直到它们被应用程序读走.通过消息队列,应用程序可独立地执行--它们不需要知道彼此的位置.或在继续执行 ...
- 成员函数的重载&&隐藏&&覆盖
/* *成员函数的重载,覆盖,隐藏 *重载: *1.同样的范围(在同一个类中) *2.函数名同样 *3.參数不同 *4.virtualkeyword可有可无 *覆盖是指派生类覆盖基类的函数,特征是: ...