错误和异常处理相关的变更
在 PHP 7 中,很多致命错误以及可恢复的致命错误,都被转换为异常来处理了。 这些异常继承自 Error 类,此类实现了 Throwable 接口 (所有异常都实现了这个基础接口)。
这也意味着,当发生错误的时候,以前代码中的一些错误处理的代码将无法被触发。 因为在 PHP 7 版本中,已经使用抛出异常的错误处理机制了。 (如果代码中没有捕获 Error 异常,那么会引发致命错误)。
PHP 7 改变了大多数错误的报告方式。不同于传统(PHP 5)的错误报告机制,现在大多数错误被作为 Error 异常抛出。
这种 Error 异常可以像 Exception 异常一样被第一个匹配的 try / catch 块所捕获。如果没有匹配的 catch 块,则调用异常处理函数(事先通过 set_exception_handler() 注册)进行处理。 如果尚未注册异常处理函数,则按照传统方式处理:被报告为一个致命错误(Fatal Error)。
Error 类并非继承自 Exception 类,所以不能用 catch (Exception $e) { ... } 来捕获 Error。你可以用 catch (Error $e) { ... },或者通过注册异常处理函数( set_exception_handler())来捕获 Error。
set_exception_handler() 不再保证收到的一定是 Exception 对象
抛出 Error 对象时,如果 set_exception_handler() 里的异常处理代码声明的类型是 Exception ,将会导致 fatal error。
想要异常处理器同时支持 PHP5 和 PHP7,应该删掉异常处理器里的类型声明。如果代码仅仅是升级到 PHP7,则可以把类型 Exception 替换成 Throwable。
<?php
// PHP 5 时代的代码将会出现问题
function handler(Exception $e) { ... }
set_exception_handler('handler');
// 兼容 PHP 5 和 7
function handler($e) { ... }
// 仅支持 PHP 7
function handler(Throwable $e) { ... }
当内部构造器失败的时候,总是抛出异常
在之前版本中,如果内部类的构造器出错,会返回 NULL 或者一个不可用的对象。 从 PHP 7 开始,如果内部类构造器发生错误, 那么会抛出异常。
解析错误会抛出 ParseError 异常
解析错误会抛出 ParseError 异常。 对于 eval() 函数,需要将其包含到一个 catch 代码块中来处理解析错误。
E_STRICT 警告级别变更
原有的 E_STRICT 警告都被迁移到其他级别。 E_STRICT 常量会被保留,所以调用 error_reporting(E_ALL|E_STRICT) 不会引发错误。
场景 | 新的级别/行为 |
---|---|
将资源类型的变量用作键来进行索引 | E_NOTICE |
抽象静态方法 | 不再警告,会引发错误 |
重复定义构造函数 | 不再警告,会引发错误 |
在继承的时候,方法签名不匹配 | E_WARNING |
在两个 trait 中包含相同的(兼容的)属性 | 不再警告,会引发错误 |
以非静态调用的方式访问静态属性 | E_NOTICE |
变量以引用的方式赋值 | E_NOTICE |
变量以引用的方式传递(到函数参数中) | E_NOTICE |
以静态方式调用非静态方法 | E_DEPRECATED |
关于变量处理的变更
PHP 7 现在使用了抽象语法树来解析源代码。这为语言带来了许多改进,之前的PHP解释器的限制所不可能实现的, 但出于一致性的原因导致了一些特殊例子的变动,而这些变动打破了向后兼容。
关于间接使用变量、属性和方法的变更
对变量、属性和方法的间接调用现在将严格遵循 从左到右 的顺序来解析,而不是之前的混杂着几个特殊案例的情况。 下面这张表说明了这个解析顺序的变化。