上手并过渡到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 { }

 

 
原文:
https://segmentfault.com/a/1190000004219265
 

上手并过渡到PHP7(4)——取代fatal error的engine exceptions的更多相关文章

  1. 上手并过渡到PHP7(1)——基于Homestead的PHP7和XDdebug环境

    PHP7 up and running 泊学实操视频泊学原文链接PHP7, Xdebug and Homestead 在经历了13个RC版本之后,PHP 7终于来了.在我们上手评估PHP 7的新特性之 ...

  2. 上手并过渡到PHP7(3)——Uniform Variable Syntax到底统一了什么

    PHP7 up and running 泊学原文链接泊学实操视频 Uniform Variable Syntax 在PHP 7提出Uniform Variable Syntax之前,我们大多数人可能都 ...

  3. 上手并过渡到PHP7(5)——轻量级“集合”迭代器-Generator

    轻量级“集合”迭代器-Generator泊学视频链接泊阅文档链接Generator是PHP 5.5加入的新语言特性.但是,它似乎并没有被很多PHP开发者广泛采用.因此,在我们了解PHP 7对Gener ...

  4. 上手并过渡到PHP7(2)——必须传递int, string, bool参数?没问题

    Type hints, Type safe 泊学实操视频 泊学原文链接PHP 7中最引人注目的新特性之一,无疑是Scalar type hints.我们可以在函数参数和返回值中使用scalar typ ...

  5. VS2010遇到fatal error C1083: 无法打开预编译头文件:“xxx.pch”: No such file or directory

    对C++和VS2010非常不熟悉,但是无奈赶着项目,只能看了点基础就上手,然后就碰到这个问题了. 原因分析: http://bbs.csdn.net/topics/340191697?page=1 编 ...

  6. PHP Fatal error: Call to undefined function mysql_connect() 错误解释

    我使用的是5.6.11版本的php 刚开始以为编译参数加了--with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd,就可以不能安装mysql了. 但是使用了mysq ...

  7. 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()....,原因是没有 ...

  8. php捕获Fatal error错误与异常处理

    php中的错误和异常是两个不同的概念. 错误:是因为脚本的问题,比如少写了分号,调用未定义的函数,除0,等一些编译语法错误. 异常:是因为业务逻辑和流程,不符合预期情况,比如验证请求参数,不通过就用 ...

  9. fatal error C1045: 编译器限制 : 链接规范嵌套太深

    前言 我相信你是遇到了同样的问题.通过搜索引擎来到这里的.为了不耽误排查问题的时间,我提前说明一下这篇文章所描述的问题范畴: 我遇到的问题和 c++ 模板相关: 如果我减少传递的参数的话,是有可能避免 ...

随机推荐

  1. configure: error: png.h not found.

    PHP的时候提示这个错误 configure: error: png.h not found.,这个是选择安装GD模块才会出现的错误,详细错误信息如下 If configure fails try - ...

  2. Error_OAF_the descriptive flexfield with application name payables and name is not frozen

    2014-06-17 BaoXinjian 1. Issue and Eroor Error: The descriptive flexfield with application name paya ...

  3. 深度解析(一六)Floyd算法

    Floyd算法(一)之 C语言详解 本章介绍弗洛伊德算法.和以往一样,本文会先对弗洛伊德算法的理论论知识进行介绍,然后给出C语言的实现.后续再分别给出C++和Java版本的实现. 目录 1. 弗洛伊德 ...

  4. Linux内核(10) - 内核中的链表

    早上上班坐地铁要排队,到了公司楼下等电梯要排队,中午吃饭要排队,下班了追求一个女孩子也要排队,甚至在网上下载个什么门的短片也要排队,每次看见人群排成一条长龙时,才真正意识到自己是龙的传人.那么下面咱们 ...

  5. 定时器quartz工具类

    一.gradle配置 // https://mvnrepository.com/artifact/org.quartz-scheduler/quartz compile group: 'org.qua ...

  6. 《Effective Java》读书笔记八(异常)

    No57 只针对异常的情况才使用异常 异常应该只用于异常的情况下,它们永远不应该用于正常的控制流. No58 对可恢复的情况使用受检异常,对编程错误使用运行时异常 Java程序设计语言提供了三种可抛出 ...

  7. OSGi中的ServletContext

    在OSGi中,不能的bundle分属不同的装载器(Class Loader), 在J2EE 应用中,不同BUNDLE 中的JSP 所相应的ServletContext对象不同,这与通常情况下的应用是不 ...

  8. 巧用tail查看软件的安装进程

    我在使用perlbrew安装perl的时候,学到的一招,呵呵. 有时候,安装软件的时候,特别是手动安装的时候,没有什么提示信息,只能干等着,其实,可以使用tail命令来跟踪安装日志的尾部,来观察安装的 ...

  9. Calendar.NET

      Please Sign up or sign in to vote.请注册或登录投票. Download Binaries 下载二进制文件 Download source 下载源代码 Introd ...

  10. c++11特性与cocos2d-x 3.0之std::bind与std::function

    昨天同事让帮忙写一小功能,才发现cocos2d-x 3.0 和 cocos2d-x 3.0rc0 差别还是相当大的. 发现Label这一个控件,3.0就比rc0版本多了一个创建函数,更为关键的是3.0 ...