在 PHP 7 中,很多致命错误以及可恢复的致命错误,都被转换为异常来处理了。 这些异常继承自 Error 类,此类实现了 Throwable 接口 (所有异常都实现了这个基础接口)。
这也意味着,当发生错误的时候,以前代码中的一些错误处理的代码将无法被触发。 因为在 PHP 7 版本中,已经使用抛出异常的错误处理机制了。 (如果代码中没有捕获 Error 异常,那么会引发致命错误)。
PHP 7 中的错误处理的更完整的描述,请参见 PHP 7 错误处理。 本迁移指导主要是列出对兼容性有影响的变更。
在之前版本中,如果内部类的构造器出错,会返回 NULL
或者一个不可用的对象。
从 PHP 7 开始,如果内部类构造器发生错误,
那么会抛出异常。
原有的 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 now uses an abstract syntax tree when parsing source files. This has permitted many improvements to the language which were previously impossible due to limitations in the parser used in earlier versions of PHP, but has resulted in the removal of a few special cases for consistency reasons, which has resulted in backward compatibility breaks. These cases are detailed in this section.
Indirect access to variables, properties, and methods will now be evaluated strictly in left-to-right order, as opposed to the previous mix of special cases. The table below shows how the order of evaluation has changed.
Expression | PHP 5 interpretation | PHP 7 interpretation |
---|---|---|
$$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']()
|
Code that used the old right-to-left evaluation order must be rewritten to explicitly use that evaluation order with curly braces (see the above middle column). This will make the code both forwards compatible with PHP 7.x and backwards compatible with PHP 5.x.
list() will now assign values to variables in the
order they are defined, rather than reverse order. In general, this only
affects the case where list() is being used in
conjunction with the array []
operator, as shown below:
<?php
list($a[], $a[], $a[]) = [1, 2, 3];
var_dump($a);
?>
Output of the above example in PHP 5:
array(3) { [0]=> int(3) [1]=> int(2) [2]=> int(1) }
Output of the above example in PHP 7:
array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) }
In general, it is recommended not to rely on the order in which list() assignments occur, as this is an implementation detail that may change again in the future.
list() constructs can no longer be empty. The following are no longer allowed:
<?php
list() = $a;
list(,,) = $a;
list($x, list(), $y) = $a;
?>
list() can no longer unpack string variables. str_split() should be used instead.
The order of the elements in an array has changed when those elements have been automatically created by referencing them in a by reference assignment. For example:
<?php
$array = [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
?>
Output of the above example in PHP 5:
array(2) { ["b"]=> &int(1) ["a"]=> &int(1) }
Output of the above example in PHP 7:
array(2) { ["a"]=> &int(1) ["b"]=> &int(1) }
Variable variables can no longer be used with the global keyword. The curly brace syntax can be used to emulate the previous behaviour if required:
<?php
function f() {
// Valid in PHP 5 only.
global $$foo->bar;
// Valid in PHP 5 and 7.
global ${$foo->bar};
}
?>
As a general principle, using anything other than a bare variable with global is discouraged.
In PHP 5, using redundant parentheses around a function parameter could quiet strict standards warnings when the function parameter was passed by reference. The warning will now always be issued.
<?php
function getArray() {
return [1, 2, 3];
}
function squareArray(array &$a) {
foreach ($a as &$v) {
$v **= 2;
}
}
// Generates a warning in PHP 7.
squareArray((getArray()));
?>
以上例程会输出:
Notice: Only variables should be passed by reference in /tmp/test.php on line 13
foreach发生了细微的变化,控制结构, 主要围绕阵列的内部数组指针和迭代处理的修改。
在PHP7之前,当数组通过 foreach 迭代时,数组指针会移动。现在开始,不再如此,见下面代码
<?php
$array = [0, 1, 2];
foreach ($array as &$val) {
var_dump(current($array));
}
?>
Output of the above example in PHP 5:
int(1) int(2) bool(false)
Output of the above example in PHP 7:
int(0) int(0) int(0)
当使用引用遍历数组时,现在 foreach 在迭代中能更好的跟踪变化。例如,在迭代中添加一个迭代值到数组中,参考下面的代码:
<?php
$array = [0];
foreach ($array as &$val) {
var_dump($val);
$array[1] = 1;
}
?>
Output of the above example in PHP 5:
int(0)
Output of the above example in PHP 7:
int(0) int(1)
迭代一个非Traversable对象将会与迭代一个引用数组的行为相同。 这将导致在对象添加或删除属性时,foreach通过引用遍历时,有更好的迭代特性也能被应用
Previously, octal literals that contained invalid numbers were silently truncated (0128 was taken as 012). Now, an invalid octal literal will cause a parse error.
Bitwise shifts by negative numbers will now throw an ArithmeticError:
<?php
var_dump(1 >> -1);
?>
Output of the above example in PHP 5:
int(0)
Output of the above example in 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
Bitwise shifts (in either direction) beyond the bit width of an integer will always result in 0. Previously, the behaviour of such shifts was architecture dependent.
Previously, when 0 was used as the divisor for either the divide (/) or
modulus (%) operators, an E_WARNING would be emitted and
false
would be returned. Now, the divide operator
returns a float as either +INF, -INF, or NAN. The modulus operator E_WARNING
has been removed and will throw a DivisionByZeroError
exception.
<?php
var_dump(3/0);
var_dump(0/0);
var_dump(0%0);
?>
Output of the above example in 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)
Output of the above example in 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"));
?>
Output of the above example in PHP 5:
bool(true) bool(true) int(15) string(2) "oo"
Output of the above example in 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 是否含有十六进制数字,并将其转换为integer:
<?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)
?>
由于新的 Unicode codepoint escape syntax语法, 紧连着无效序列并包含\u{ 的字串可能引起致命错误。 为了避免这一报错,应该避免反斜杠开头。
这两个函数从PHP 4.1.0开始被废弃,应该使用call_user_func() 和 call_user_func_array()。 你也可以考虑使用 变量函数 或者 ... 操作符。
已废弃的 mcrypt_generic_end() 函数已被移除,请使用mcrypt_generic_deinit()代替。
此外,已废弃的 mcrypt_ecb(),
mcrypt_cbc(), mcrypt_cfb() 和
mcrypt_ofb() 函数已被移除,请配合恰当的MCRYPT_MODE_*
常量来使用 mcrypt_decrypt()进行代替。
已废弃的 datefmt_set_timezone_id() 和 IntlDateFormatter::setTimeZoneID() 函数已被移除,请使用 datefmt_set_timezone() 与 IntlDateFormatter::setTimeZone()代替。
set_magic_quotes_runtime(), 和它的别名 magic_quotes_runtime()已被移除. 它们在PHP 5.3.0中已经被废弃,并且 在in PHP 5.4.0也由于魔术引号的废弃而失去功能。
已废弃的 set_socket_blocking() 函数已被移除,请使用stream_set_blocking()代替。
Support for PostScript Type1 fonts has been removed from the GD extension, resulting in the removal of the following functions:
Using TrueType fonts and their associated functions is recommended instead.
The following INI directives have been removed as their associated features have also been removed:
xsl.security_prefs
The xsl.security_prefs
directive has been removed.
Instead, the XsltProcessor::setSecurityPrefs()
method should be called to control the security preferences on a
per-processor basis.
new 语句创建的对象不能 以引用的方式赋值给变量。
<?php
class C {}
$c =& new C;
?>
Output of the above example in PHP 5:
Deprecated: Assigning the return value of new by reference is deprecated in /tmp/test.php on line 3
Output of the above example in 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 代码的方式被移除。 受到影响的标签有:
开标签 | 闭标签 |
---|---|
<% |
%> |
<%= |
%> |
<script language="php"> |
</script> |
在不匹配的上下文中以静态方式调用非静态方法, 在 PHP 5.6 中已经废弃, 但是在 PHP 7.0 中, 会导致被调用方法中未定义 $this 变量,以及此行为已经废弃的警告。
<?php
class A {
public function test() { var_dump($this); }
}
// 注意:并没有从类 A 继承
class B {
public function callNonStaticMethodOfA() { A::test(); }
}
(new B)->callNonStaticMethodOfA();
?>
Output of the above example in PHP 5:
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) { }
Output of the above example in 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) {
//
}
?>
在 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 扩展取代。 对于数值的处理,有以下两点需要注意的: 第一,数值不能以点号(.)结束 (例如,数值 34. 必须写作 34.0 或 34)。 第二,如果使用科学计数法表示数值,e 前面必须不是点号(.) (例如,3.e3 必须写作 3.0e3 或 3e3)。
将浮点数转换为整数的时候,如果浮点数值太大,导致无法以整数表达的情况下,
在之前的版本中,内部函数会直接将整数截断,并不会引发错误。
在 PHP 7.0 中,如果发生这种情况,会引发 E_WARNING 错误,并且返回 NULL
。
在自定义会话处理器中,如果函数的返回值不是 FALSE
,也不是 -1,
会引发致命错误。现在,如果这些函数的返回值不是布尔值,也不是 -1
或者 0,函数调用结果将被视为失败,并且引发 E_WARNING 错误。