向后不兼容更改

错误和异常处理的更改

在 PHP 7 中,许多致命错误和可恢复致命错误已转换为异常。这些错误异常继承自 Error 类,该类本身实现了 Throwable 接口(所有异常继承的新基础接口)。

这意味着自定义错误处理程序可能不再被触发,因为可能会抛出异常(导致未捕获的 Error 异常的新致命错误)。

有关 PHP 7 中错误如何工作的更完整描述,请参见 PHP 7 错误页面。此迁移指南仅列出影响向后兼容性的更改。

set_exception_handler() 不再保证接收 Exception 对象

使用 Exception 类型声明为 set_exception_handler() 注册异常处理程序的代码,当抛出 Error 对象时会导致致命错误。

如果处理程序需要在 PHP 5 和 7 上运行,则应从处理程序中删除类型声明,而迁移到仅在 PHP 7 上运行的代码可以简单地将 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 或不可用的对象。现在所有内部类在这种情况下都会抛出 Exception,与用户类已有的行为相同。

解析错误抛出 ParseError

解析器错误现在会抛出 ParseError 对象。对 eval() 的错误处理现在应包含一个 catch 块,可以处理此错误。

E_STRICT 通知严重性更改

所有 E_STRICT 通知已重新分类为其他级别。E_STRICT 常量保留,因此像 error_reporting(E_ALL|E_STRICT) 这样的调用不会导致错误。

E_STRICT 通知严重性更改
情况 新级别/行为
通过资源索引 E_NOTICE
抽象静态方法 通知已删除,不触发任何错误
"重新定义"构造函数 通知已删除,不触发任何错误
继承期间签名不匹配 E_WARNING
两个使用的特征中具有相同(兼容)的属性 通知已删除,不触发任何错误
非静态访问静态属性 E_NOTICE
只有变量应该通过引用赋值 E_NOTICE
只有变量应该通过引用传递 E_NOTICE
静态调用非静态方法 E_DEPRECATED

变量处理的更改

PHP 7 现在在解析源文件时使用抽象语法树。这允许对语言进行许多改进,这些改进以前由于早期 PHP 版本中使用的解析器的限制而无法实现,但由于一致性原因导致删除了一些特例,从而导致向后兼容性中断。本节将详细介绍这些情况。

对间接变量、属性和方法的处理的更改

间接访问变量、属性和方法现在将严格按照从左到右的顺序进行评估,而不是以前混合使用的特例。下表显示了评估顺序是如何改变的。

间接表达式的旧和新评估
表达式 PHP 5 解释 PHP 7 解释
$$foo['bar']['baz'] ${$foo['bar']['baz']} ($$foo)['bar']['baz']
$foo->$bar['baz'] $foo->{$bar['baz']} ($foo->$bar)['baz']
$foo->$bar['baz']() $foo->{$bar['baz']}() ($foo->$bar)['baz']()
Foo::$bar['baz']() Foo::{$bar['baz']}() (Foo::$bar)['baz']()

使用旧的从右到左评估顺序的代码必须重写,以使用大括号显式使用该评估顺序(参见上面的中间列)。这将使代码与 PHP 7.x 向前兼容,并与 PHP 5.x 向后兼容。

这也影响了 global 关键字。如果需要,可以使用大括号语法来模拟以前的行为

<?php
function f() {
// 仅在 PHP 5 中有效。
global $$foo->bar;

// 在 PHP 5 和 7 中有效。
global ${$foo->bar};
}
?>

list() 处理的更改

list() 不再以相反的顺序分配变量

list() 现在将按定义的顺序将值分配给变量,而不是相反的顺序。通常,这仅影响在与数组 [] 运算符一起使用时使用 list() 的情况,如下所示

<?php
list($a[], $a[], $a[]) = [1, 2, 3];
var_dump($a);
?>

上述示例在 PHP 5 中的输出

array(3) {
  [0]=>
  int(3)
  [1]=>
  int(2)
  [2]=>
  int(1)
}

上述示例在 PHP 7 中的输出

array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}

通常,建议不要依赖 list() 赋值发生的顺序,因为这是可能在将来再次更改的实现细节。

已删除空的 list() 赋值

list() 结构不能再为空。以下不再允许

<?php
list() = $a;
list(,,) =
$a;
list(
$x, list(), $y) = $a;
?>
list() 不能解包 strings

list() 不能再解包 string 变量。应改为使用 str_split()

通过引用赋值时自动创建元素时的数组排序已更改

数组中元素的顺序已更改,当这些元素通过引用赋值自动创建时。例如

<?php
$array
= [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
?>

上述示例在 PHP 5 中的输出

array(2) {
  ["b"]=>
  &int(1)
  ["a"]=>
  &int(1)
}

上述示例在 PHP 7 中的输出

array(2) {
  ["a"]=>
  &int(1)
  ["b"]=>
  &int(1)
}

函数参数中的括号不再影响行为

在 PHP 5 中,在函数参数周围使用多余的括号可以消除严格标准警告,前提是函数参数是通过引用传递的。现在将始终发出警告。

<?php
function getArray() {
return [
1, 2, 3];
}

function
squareArray(array &$a) {
foreach (
$a as &$v) {
$v **= 2;
}
}

// 在 PHP 7 中会生成警告。
squareArray((getArray()));
?>

上面的例子将输出

Notice: Only variables should be passed by reference in /tmp/test.php on line 13

foreach 的更改

foreach 控制结构的行为进行了微小的更改,主要涉及对内部数组指针的处理以及对正在迭代的数组的修改。

foreach 不再更改内部数组指针

在 PHP 7 之前,当使用 foreach 迭代数组时,会修改内部数组指针。现在不再是这样,如以下示例所示

<?php
$array
= [0, 1, 2];
foreach (
$array as &$val) {
var_dump(current($array));
}
?>

上述示例在 PHP 5 中的输出

int(1)
int(2)
bool(false)

上述示例在 PHP 7 中的输出

int(0)
int(0)
int(0)

按值 foreach 对数组的副本进行操作

当以默认的按值模式使用时,foreach 现在将对正在迭代的数组的副本进行操作,而不是数组本身。这意味着在迭代期间对数组进行的更改不会影响正在迭代的值。

按引用 foreach 改进了迭代行为

当按引用迭代时,foreach 现在可以更好地跟踪在迭代期间对数组所做的更改。例如,在迭代期间追加到数组现在将导致追加的值也被迭代。

<?php
$array
= [0];
foreach (
$array as &$val) {
var_dump($val);
$array[1] = 1;
}
?>

上述示例在 PHP 5 中的输出

int(0)

上述示例在 PHP 7 中的输出

int(0)
int(1)

Traversable 对象的迭代

迭代非 Traversable 对象现在将具有与迭代按引用数组相同的行为。这导致 在迭代期间修改数组时改进的行为 也适用于在对象中添加或删除属性的情况。

int 处理的更改

无效的八进制字面量

以前,包含无效数字的八进制字面量会被静默截断(0128 被视为 012)。现在,无效的八进制字面量会导致解析错误。

负位移

用负数进行位运算移位现在将抛出 ArithmeticError

<?php
var_dump
(1 >> -1);
?>

上述示例在 PHP 5 中的输出

int(0)

上述示例在 PHP 7 中的输出

Fatal error: Uncaught ArithmeticError: Bit shift by negative number in /tmp/test.php:2
Stack trace:
#0 {main}
  thrown in /tmp/test.php on line 2

超出范围的位移

超出 int 位宽的位移(任何方向)将始终导致 0。以前,此类位移的行为取决于体系结构。

对除以零的更改

以前,当 0 用作除法 (/) 或取模 (%) 运算符的除数时,会发出 E_WARNING 并返回 **false**。现在,除法运算符返回浮点数,如 +INF、-INF 或 NAN,如 IEEE 754 所规定。取模运算符 E_WARNING 已被删除,并将抛出 DivisionByZeroError 异常。

<?php
var_dump
(3/0);
var_dump(0/0);
var_dump(0%0);
?>

上述示例在 PHP 5 中的输出

Warning: Division by zero in %s on line %d
bool(false)

Warning: Division by zero in %s on line %d
bool(false)

Warning: Division by zero in %s on line %d
bool(false)

上述示例在 PHP 7 中的输出

Warning: Division by zero in %s on line %d
float(INF)

Warning: Division by zero in %s on line %d
float(NAN)

PHP Fatal error:  Uncaught DivisionByZeroError: Modulo by zero in %s line %d

string 处理的更改

十六进制字符串不再被视为数字

包含十六进制数字的字符串不再被视为数字。例如

<?php
var_dump
("0x123" == "291");
var_dump(is_numeric("0x123"));
var_dump("0xe" + "0x1");
var_dump(substr("foo", "0x1"));
?>

上述示例在 PHP 5 中的输出

bool(true)
bool(true)
int(15)
string(2) "oo"

上述示例在 PHP 7 中的输出

bool(false)
bool(false)
int(0)

Notice: A non well formed numeric value encountered in /tmp/test.php on line 5
string(3) "foo"

filter_var() 可用于检查 string 是否包含十六进制数字,以及将这种类型的字符串转换为 int

<?php
$str
= "0xffff";
$int = filter_var($str, FILTER_VALIDATE_INT, FILTER_FLAG_ALLOW_HEX);
if (
false === $int) {
throw new
Exception("Invalid integer!");
}
var_dump($int); // int(65535)
?>

\u{ 可能会导致错误

由于添加了新的 Unicode 代码点转义语法,包含字面量 \u{ 后跟无效序列的字符串将导致致命错误。为了避免这种情况,应转义前导反斜杠。

已删除的函数

call_user_method()call_user_method_array()

这些函数在 PHP 4.1.0 中被弃用,取而代之的是 call_user_func()call_user_func_array()。您可能还想考虑使用 可变函数 和/或 ... 运算符。

所有 ereg* 函数

所有 ereg 函数都被删除。建议使用 PCRE 作为替代。

mcrypt 别名

已弃用的 mcrypt_generic_end() 函数已被删除,取而代之的是 mcrypt_generic_deinit()

此外,已弃用的 mcrypt_ecb()mcrypt_cbc()mcrypt_cfb()mcrypt_ofb() 函数已被删除,取而代之的是使用 mcrypt_decrypt() 以及相应的 MCRYPT_MODE_* 常量。

所有 ext/mysql 函数

所有 ext/mysql 函数都被删除。有关选择不同 MySQL API 的详细信息,请参阅 选择 MySQL API

所有 ext/mssql 函数

所有 ext/mssql 函数都被删除。

intl 别名

已弃用的 datefmt_set_timezone_id()IntlDateFormatter::setTimeZoneID() 别名已被删除,取而代之的是 datefmt_set_timezone()IntlDateFormatter::setTimeZone()

set_magic_quotes_runtime()

set_magic_quotes_runtime() 及其别名 magic_quotes_runtime() 已被删除。它们在 PHP 5.3.0 中被弃用,并在 PHP 5.4.0 中删除魔术引号后,实际上变得不再起作用。

set_socket_blocking()

已弃用的 set_socket_blocking() 别名已移除,建议使用 stream_set_blocking()

dl() 在 PHP-FPM 中

dl() 在 PHP-FPM 中不再可用。它在 CLI 和嵌入式 SAPIs 中仍然可用。

GD Type1 函数

GD 扩展已移除对 PostScript Type1 字体的支持,导致以下函数被移除

  • imagepsbbox()
  • imagepsencodefont()
  • imagepsextendfont()
  • imagepsfreefont()
  • imagepsloadfont()
  • imagepsslantfont()
  • imagepstext()

建议使用 TrueType 字体及其相关函数。

已移除 INI 指令

已移除的功能

以下 INI 指令已被移除,因为它们关联的功能也被移除

  • always_populate_raw_post_data
  • asp_tags

xsl.security_prefs

xsl.security_prefs 指令已被移除。应改用 XsltProcessor::setSecurityPrefs() 方法来控制每个处理器的安全偏好。

其他向后不兼容的更改

无法通过引用分配新对象

new 语句的结果不再可以通过引用分配给变量

<?php
class C {}
$c =& new C;
?>

上述示例在 PHP 5 中的输出

Deprecated: Assigning the return value of new by reference is deprecated in /tmp/test.php on line 3

上述示例在 PHP 7 中的输出

Parse error: syntax error, unexpected 'new' (T_NEW) in /tmp/test.php on line 3

无效的类、接口和特征名

以下名称不能用于命名类、接口或特征

此外,以下名称也不应使用。虽然它们在 PHP 7.0 中不会产生错误,但它们是为将来使用而保留的,应被视为已弃用。

已移除 ASP 和脚本 PHP 标签

已移除使用 ASP 和脚本标签来分隔 PHP 代码的支持。受影响的标签是

已移除 ASP 和脚本标签
开始标签 结束标签
<% %>
<%= %>
<script language="php"> </script>

已移除来自不兼容上下文的调用

之前在 PHP 5.6 中已弃用,对非静态方法进行静态调用,并且上下文不兼容,现在将导致调用的方法具有未定义的 $this 变量,并发出弃用警告。

<?php
class A {
public function
test() { var_dump($this); }
}

// 注意:不继承 A
class B {
public function
callNonStaticMethodOfA() { A::test(); }
}

(new
B)->callNonStaticMethodOfA();
?>

以上示例在 PHP 5.6 中的输出

Deprecated: Non-static method A::test() should not be called statically, assuming $this from incompatible context in /tmp/test.php on line 8
object(B)#1 (0) {
}

上述示例在 PHP 7 中的输出

Deprecated: Non-static method A::test() should not be called statically in /tmp/test.php on line 8

Notice: Undefined variable: this in /tmp/test.php on line 3
NULL

yield 现在是右结合运算符

yield 结构不再需要括号,并且已更改为右结合运算符,其优先级介于 print=> 之间。这可能会导致行为改变

<?php
echo yield -1;
// 之前被解释为
echo (yield) - 1;
// 现在被解释为
echo yield (-1);

yield
$foo or die;
// 之前被解释为
yield ($foo or die);
// 现在被解释为
(yield $foo) or die;
?>

可以使用括号来消除这些情况的歧义。

函数不能有多个同名参数

不再允许定义两个或多个同名函数参数。例如,以下函数将触发 E_COMPILE_ERROR

<?php
function foo($a, $b, $unused, $unused) {
//
}
?>

检查参数的函数报告*当前*参数值

func_get_arg()func_get_args()debug_backtrace() 和异常回溯不再报告传递给参数的原始值,而是提供当前值(可能已被修改)。

<?php
function foo($x) {
$x++;
var_dump(func_get_arg(0));
}
foo(1);?>

上述示例在 PHP 5 中的输出

1

上述示例在 PHP 7 中的输出

2

switch 语句不能有多个 default 块

不再允许在 switch 语句中定义两个或多个 default 块。例如,以下 switch 语句将触发 E_COMPILE_ERROR

<?php
switch (1) {
default:
break;
default:
break;
}
?>

$HTTP_RAW_POST_DATA 已移除

$HTTP_RAW_POST_DATA 不再可用。应改用 php://input 流。

# 注释在 INI 文件中已移除

已移除在 INI 文件中使用 # 来前缀注释的支持。应改用 ;(分号)。此更改适用于 php.ini,以及由 parse_ini_file()parse_ini_string() 处理的文件。

JSON 扩展已替换为 JSOND

JSON 扩展已替换为 JSOND,导致三个小型的 BC 问题。首先,数字不能以小数点结尾(即 34. 必须更改为 34.034)。其次,使用科学记数法时,e 指数不能紧接在小数点之后(即 3.e3 必须更改为 3.0e33e3)。最后,空字符串不再被视为有效的 JSON。

内部函数在溢出时发生故障

以前,内部函数会静默地截断从浮点数到整数强制转换产生的数字,当浮点数太大而无法表示为整数时。现在,将发出 E_WARNING 并返回 null

对自定义会话处理程序返回值的修复

由自定义会话处理程序实现的任何谓词函数,如果返回 false-1,都将是致命错误。如果这些函数返回除布尔值、-10 之外的任何值,则它将失败并发出 E_WARNING。

相等元素的排序顺序

内部排序算法已得到改进,这可能会导致比较为相等的元素的排序顺序与之前不同。

注意:

不要依赖比较为相等的元素的顺序;它随时可能改变。

放置错误的 break 和 continue 语句

breakcontinue 语句不在循环或 switch 控制结构中,现在在编译时检测到,而不是像以前一样在运行时检测到,并将触发 E_COMPILE_ERROR

Mhash 不再是扩展

Mhash 扩展已完全集成到 Hash 扩展中。因此,不再可以使用 extension_loaded() 来检测 Mhash 支持;应改用 function_exists()。此外,Mhash 不再由 get_loaded_extensions() 及其相关功能报告。

declare(ticks)

declare(ticks) 指令不再泄漏到不同的编译单元。

添加说明

用户贡献的说明

此页面没有用户贡献的说明。
To Top