2024年PHP开发者大会日本站

向后不兼容的更改

错误和异常处理的更改

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
两个使用的trait中具有相同的(兼容的)属性 删除提示,不触发任何错误
非静态地访问静态属性 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() 不能解包 字符串

list() 不再能解包 字符串 变量。应该使用 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 对象的行为现在与按引用迭代数组的行为相同。这导致 在迭代期间修改数组时的改进行为 也适用于向对象添加或删除属性的情况。

整数 处理的更改

无效的八进制字面量

以前,包含无效数字的八进制字面量会被静默截断(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

超出范围的位移

超出 整数 位宽的位移(任何方向)将始终导致结果为 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

字符串 处理的更改

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

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

<?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() 可用于检查 字符串 是否包含十六进制数字,也可用于将该类型的字符串转换为 整数

<?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 中

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

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

无效的类、接口和trait名称

以下名称不能用于命名类、接口或trait:

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

已移除ASP和script PHP标签

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

已移除的ASP和script标签
起始标签 结束标签
<% %>
<%= %>
<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 语句

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

不允许将常量作为 break 和 continue 参数

breakcontinue语句不再允许其参数为常量,并触发E_COMPILE_ERROR

Mhash 不再是一个扩展

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

declare(ticks)

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

添加注释

用户贡献的笔记

此页面没有用户贡献的笔记。
To Top