PHP 7中许多致命错误和可恢复致命错误已转换为异常。这些错误异常继承自Error类,该类本身实现了Throwable接口(所有异常继承的新基接口)。
这意味着自定义错误处理程序可能不再被触发,因为可能会抛出异常(导致未捕获的Error异常出现新的致命错误)。
可以在PHP 7错误页面上找到有关PHP 7中错误如何操作的更完整描述。本迁移指南仅列举影响向后兼容性的更改。
使用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) { ... }
?>
解析器错误现在会抛出一个ParseError对象。eval()的错误处理现在应该包括一个可以处理此错误的catch
块。
所有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中使用的解析器的限制而无法实现,但由于一致性原因导致删除了一些特例,从而导致向后兼容性中断。这些情况在本节中详细说明。
现在将严格地从左到右评估对变量、属性和方法的间接访问,而不是以前的特殊情况混合。下表显示了评估顺序的变化。
表达式 | 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()与数组[]
运算符一起使用的情况,如下所示
<?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() 不再能解包 字符串 变量。应该使用 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 控制结构的行为进行了一些小的更改,主要涉及内部数组指针的处理和正在迭代的数组的修改。
在 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 现在能够更好地跟踪迭代期间对数组所做的更改。例如,在迭代期间追加到数组现在也会导致对追加的值进行迭代。
<?php
$array = [0];
foreach ($array as &$val) {
var_dump($val);
$array[1] = 1;
}
?>
上述示例在PHP 5中的输出
int(0)
上述示例在PHP 7中的输出
int(0) int(1)
迭代非 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{
后跟无效序列的字符串将导致致命错误。为避免这种情况,应转义开头的反斜杠。
这些函数在 PHP 4.1.0 中已被弃用,推荐使用 call_user_func() 和 call_user_func_array()。您可能还需要考虑使用 可变函数 和/或 ...
运算符。
所有 ereg
函数均已移除。建议使用 PCRE 作为替代。
已弃用的 mcrypt_generic_end() 函数已被移除,推荐使用 mcrypt_generic_deinit()。
此外,已弃用的 mcrypt_ecb()、mcrypt_cbc()、mcrypt_cfb() 和 mcrypt_ofb() 函数已被移除,推荐使用 mcrypt_decrypt() 函数并使用相应的 **MCRYPT_MODE_*
** 常量。
所有 ext/mysql 函数均已移除。有关选择其他 MySQL API 的详细信息,请参阅 选择 MySQL API。
已弃用的 datefmt_set_timezone_id() 和 IntlDateFormatter::setTimeZoneID() 别名已被移除,推荐使用 datefmt_set_timezone() 和 IntlDateFormatter::setTimeZone()。
已移除set_magic_quotes_runtime()及其别名magic_quotes_runtime()。它们在PHP 5.3.0中已弃用,并在PHP 5.4.0中移除魔术引号后实际上不再起作用。
已移除弃用的set_socket_blocking()别名,并替换为stream_set_blocking()。
GD扩展已移除对PostScript Type1字体的支持,导致以下函数被移除:
建议改用TrueType字体及其相关函数。
由于其关联功能也被移除,以下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:
此外,不应使用以下名称。虽然它们在PHP 7.0中不会产生错误,但它们是为将来使用而保留的,应视为已弃用。
已移除使用ASP和script标签来分隔PHP代码的支持。受影响的标签是:
起始标签 | 结束标签 |
---|---|
<% |
%> |
<%= |
%> |
<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 结构不再需要括号,并且已更改为右结合运算符,其优先级介于 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语句将触发E_COMPILE_ERROR
<?php
switch (1) {
default:
break;
default:
break;
}
?>
$HTTP_RAW_POST_DATA已不再可用。应改用php://input
流。
#
注释已移除在INI文件中使用#
作为注释前缀的支持。应改用;
(分号)。此更改适用于php.ini以及由parse_ini_file()和parse_ini_string()处理的文件。
JSON扩展已替换为JSOND,导致三个轻微的BC中断。首先,数字不能以小数点结尾(即34.
必须更改为34.0
或34
)。其次,使用科学计数法时,e
指数不能紧跟在小数点之后(即3.e3
必须更改为3.0e3
或3e3
)。最后,空字符串不再被视为有效的JSON。
以前,当浮点数太大而无法表示为整数时,内部函数会在浮点数到整数强制转换产生的数字被静默截断。现在,将发出E_WARNING并返回null
。
自定义会话处理程序实现的任何谓词函数,如果返回false
或-1
,都将是致命错误。如果这些函数返回的值不是布尔值、-1
或0
,则会失败并发出E_WARNING。
内部排序算法已改进,这可能导致与以前相比,比较结果相等的元素的排序顺序不同。
注意:
不要依赖比较结果相等的元素的顺序;它随时可能改变。
循环或switch
控制结构之外的break
和continue
语句现在在编译时而不是像以前那样在运行时被检测到,并触发E_COMPILE_ERROR
。
break
和continue
语句不再允许其参数为常量,并触发E_COMPILE_ERROR
。
Mhash扩展已完全集成到Hash扩展中。因此,不再可以使用extension_loaded()检测Mhash支持;请改用function_exists()。此外,Mhash不再由get_loaded_extensions()和相关功能报告。
declare(ticks)指令不再泄漏到不同的编译单元。