许多的Fatal错误,包括一些可以被修正的Fatal错误,在PHP7中以Exceptions异常对待。这些Error Exceptions继承于 Error 类。而 Error 类则继承于异常基类 Throwable 接口。
PHP7中详细的Error相关的信息可以参考页面[ PHP7错误 ]。本文中仅仅介绍和向后兼容有关的信息如下。
在PHP7之前,类内部的构造函数在失败时总是返回NULL或者返回一个不可用的Object,但此版本开始,在构造函数初始化失败时总是会抛出异常。
解析错误时会抛出 解析异常
Parser errors now throw a ParseError object. Error handling for eval() should now include a catch block that can handle this error. 解析错误,现在开始会抛出一个 解析异常 对象。eval() 函数现在开始可以通过 catch 捕捉异常,随之做相应处理。
所有E_STRICT级别的报错已重新分配到其他报错等级中。E_STRICT常量依然保留,所以当你设置报错等级为 **error_reporting(E_ALL|E_STRICT)**时,不会引起报错。
变更情况如下表
PHP7开始使用一种抽象的语法树来解析PHP代码文件。老版本的PHP因为PHP解析器的局限性是不可能实现这一特性的。但此处的改动引起了一些一致性问题,破坏了向后兼容性。本节详细介绍这块的情况。
间接的使用变量、属性、方法,现在开始严格按照从左到右的顺序执行,而不是以前混合各种形式产生各种可能。下表表明的这一改变引起的差异。 这块使用老得从右到左的方式的代码,必须重写了。通过花括号来明确顺序(见上图中间列),以使代码向前兼容PHP7.x,并向后兼容PHP5.x。
对于 list() 函数处理上的修改
list() 不再按照相反顺序插入元素
list()函数从此开始按照原数组中的顺序插入到函数参数制定的位置上,不再翻转数据。这点修改只会作用在list()函数参数一起用了数组的[]符号时。举例如下:
<?php
list($a[], $a[], $a[]) = [1, 2, 3];
var_dump($a);
?>
上述例子在PHP5中的输出为:
array(3) {
[0]=>
int(3)
[1]=>
int(2)
[2]=>
int(1)
}
而在PHP7中的输出为:
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
在实际开发中,不建议使用依靠 list() 函数的参数来做排顺序这一操作,毕竟这样的hack用法在未来还是有可能调整。
list() 函数参数不再允许为空
list() 构造时不再允许参数为空的情况,下列情况将不再支持!
<?php
list() = $a;
list(,,) = $a;
list($x, list(), $y) = $a;
?>
list() 函数不再支持拆解字符串
list() 不再允许拆解字符串变量为字母,(str_split())[http://php.net/manual/en/function.str-split.php]函数可以用于做此事。
数组中的元素在通过引用方式创建时,其数组顺序会被自动的改变。例如:
<?php
$array = [];
$array["a"] =& $array["b"];
$array["b"] = 1;
var_dump($array);
?>
PHP5中的输出:
array(2) {
["b"]=>
&int(1)
["a"]=>
&int(1)
}
PHP7中的输出
array(2) {
["a"]=>
&int(1)
["b"]=>
&int(1)
}
Global 仅支持简单的变量
变量为值的变量的情况将不能再使用Global标记。如果真的需要,可以用花括号来间隔开写,例如下面代码:
<?php
function f() {
// Valid in PHP 5 only.
global $$foo->bar;
// Valid in PHP 5 and 7.
global ${$foo->bar};
}
?>
作为一个基本原则,这样的变量套变量的使用方式,在Global这种场景下是不被提倡的。
在PHP5中,参数若使被引用的并且使用括号,会没有报错发生。但在PHP7开始,这种场景都会印发一个报错。
<?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 的改变
关于 foreach 的修改比较少,主要是修改了数组遍历时的数组指针,以及修改了数组的迭代。
foreach 遍历期间不再修改数组指针
在PHP7之前,当数组通过foreach迭代时,数组指针会移动。现在开始,不再如此,见下面代码:
<?php
$array = [0, 1, 2];
foreach ($array as &$val) {
var_dump(current($array));
}
?>
PHP5中的输出
int(1)
int(2)
bool(false)
PHP7中的输出
int(0)
int(0)
int(0)
foreach 通过值遍历时,操作的值为数组的副本
当默认使用通过值遍历数组时,foreach实际操作的是数组的迭代副本,而非数组本身。这就意味着,foreach中的操作不会修改原数组的值。
foreach 通过引用遍历时,有更好的迭代特性
当使用引用遍历数组时,现在foreach在迭代中更好的跟踪变化。例如,在迭代中添加一个迭代值到数组中,例如下面代码:
<?php
$array = [0];
foreach ($array as &$val) {
var_dump($val);
$array[1] = 1;
}
?>
在PHP5的输出为:
int(0)
在PHP7的输出为:
int(0)
int(1)
non-Traversable 对象的遍历
non-Traversable 对象的遍历与通过引用遍历相似,具有相同的行为特性,在遍历期间对原数据进行的操作将会被感知。
整形处理上的调整
此前,八进制中包含无效数据会自动被截断(0128被当做为012)。现在,一个无效的八进制字面会造成分析错误。
位移的负数将抛出一个 ArithmeticError
<?php
var_dump(1 >> -1);
?>
PHP5中的输出:
int(0)
PHP7中的输出:
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。以前,这种转变的行为是依赖于运行环境的机器架构结构。
字符串处理上的调整
含十六进制字符串不再被认为是数字。例如:
<?php
var_dump("0x123" == "291");
var_dump(is_numeric("0x123"));
var_dump("0xe" + "0x1");
var_dump(substr("foo", "0x1"));
?>
在PHP5中得输出:
bool(true)
bool(true)
int(15)
string(2) "oo"
在PHP7中得输出:
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)
?>
由于新的Unicode转译语法,字符串中含有 **\u{ ** 时会触发Fatal错误。为了避免这一报错,应该避免反斜杠开头。
这些函数被在PHP4.1.0开始被标记为过时的,在PHP7开始被删除。建议使用 call_user_func() 和 call_user_func_array() 。你可以考虑下 变量函数或者其他的选择。
mcrypt 相关的
mcrypt_generic_end() 被删除,建议使用 mcrypt_generic_deinit() 。 此外,废弃的mcrypt_ecb(),mcrypt_cbc(),mcrypt_cfb()和mcrypt_ofb()功能,建议使用目前还支持的mcrypt_decrypt()与适当的MCRYPT_MODE_*常量。
intl 相关的
datefmt_set_timezone_id()与IntlDateFormatter::setTimeZoneID()别名被删除,建议使用datefmt_set_timezone()与IntlDateFormatter::setTimeZone()。
set_magic_quotes_runtime()与它的别名函数magic_quotes_runtime()都在PHP7中删除了。他们在PHP5.3.0中就被标记被过时的。
set_socket_blocking()已被移除,建议使用stream_set_blocking()。
dl() 在PHP-FPM中
dl()函数不能在PHP-FPM中使用了,它的功能做在了CLI、嵌入到SAPIs中了。
GD 类型的函数
PostScript Type1字体的支持已经从GD扩展删除,涉及的函数有:
- imagepsbbox()
- imagepsencodefont()
- imagepsextendfont()
- imagepsfreefont()
- imagepsloadfont()
- imagepsslantfont()
- imagepstext() 建议使用TrueType字体和其相关的功能代替。
下面的INI指令以及相关的功能被删除:
xsl.security_prefs指令已被删除。相反,该xsltprocessor::setsecurityprefs()方法用于控制在每个处理器上的安全选项。
New 对象不能被引用分配
New语句的结果不再能通过引用赋值给一个变量,如下代码:
<?php
class C {}
$c =& new C;
?>
PHP5中的输出:
Deprecated: Assigning the return value of new by reference is deprecated in /tmp/test.php on line 3
PHP7中的输出:
Parse error: syntax error, unexpected 'new' (T_NEW) in /tmp/test.php on line 3
下面的名称不能被用来类、接口、特性的名称:
- bool
- int
- float
- string
- NULL
- TRUE
- FALSE 此外,下列名称不应该被使用。虽然他们不会产生在PHP 7中的一个错误,他们是保留供将来使用,应认为已过时。
- resource
- object
- mixed
- numeric
使用ASP脚本标签,或者Script的PHP代码,已被删除。受影响的标签是:
之前PHP5.6的过时说明中,静态调用一个非静态方法,会在静态调用中被提示未定义 $this ,并会报错。
<?php
class A {
public function test() { var_dump($this); }
}
// Note: Does NOT extend A
class B {
public function callNonStaticMethodOfA() { A::test(); }
}
(new B)->callNonStaticMethodOfA();
?>
在PHP5中会输出:
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) {
}
在PHP7中会输出:
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;
// Was previously interpreted as
echo (yield) - 1;
// And is now interpreted as
echo yield (-1);
yield $foo or die;
// Was previously interpreted as
yield ($foo or die);
// And is now interpreted as
(yield $foo) or die;
?>
括号可以用来消除歧义的情况。
不允许函数在参数中出现相同名称的参数。例如下列代码,将会产生 E_COMPILE_ERROR 的报错。
<?php
function foo($a, $b, $unused, $unused) {
//
}
?>
$HTTP_RAW_POST_DATA 不再被支持。 可以使用 php://input 流数据来代替实现。
INI文件中以#符号作为注释的内容已被移除,;符号将代替#,这个改变同样适用于PHP.ini文件,以及parse_ini_file()和parse_ini_string()处理文件期间。
暂无