php5.5 升级到 php7.2

基准性能测试报告:

https://wx3.sinaimg.cn/mw690/006CR1TPgy1friykqt287j30d20bgwf7.jpg

官方升级指南

  1. 从 PHP 5.5.x 迁移到 PHP 5.4.x➫
  2. 从 PHP 5.6.x 迁移到 PHP 7.0.x➫
  3. 从 PHP 7.0.x 迁移到 PHP 7.1.x➫
  4. 从 PHP 7.1.x 迁移到 PHP 7.2.x➫

升级到7.2后可用的主要新特性

  1. 支持使用表达式定义常量。如:const TWO = ONE * 2;【5.6+】
  2. 新增语法糖:使用 ... 运算符定义变长参数函数。如:function fn($a, $b = null, ...$params) {}【5.6+】
  3. 新增语法糖:使用 ... 运算符进行参数展开。类似 Ruby 中的连接运算符特性。【5.6+】
  4. 新增使用 ** 进行幂运算。如:printf("2 ** 3 == %d\n", 2 ** 3);【5.6+】
  5. 扩展 use 运算符用以支持在类中导入外部的函数和常量。【5.6+】
  6. SAPI 模块中实现了一个交互式调试器phpdbg。【5.6+】
  7. 支持 php://input 可以多次打开并读取。【5.6+】
  8. 支持大文件(大于 2GB)上传。【5.6+】
  9. GMP 支持运算符重载。【5.6+】
  10. 新加 hash_equals() 比较字符串函数可避免时序攻击。【5.6+】
  11. 新增加 __debugInfo(),当使用 var_dump() 输出对象的时候, 可以用来控制要输出的属性和值。【5.6+】
  12. 新增 gost-crypto 散列算法。【5.6+】
  13. 对 SSL/TLS 的支持进行了大幅度的提升。【5.6+】
  14. 支持通过 define() 定义常量数组 【7.0+】
  15. 支持通过 new class 来实例化一个匿名类,这可以用来替代一些“用后即焚”的完整类定义。【7.0+】
  16. 新增的函数 intdiv() 用来进行整数的除法运算。 【7.0+】
  17. 支持标量类型声明(有两种模式: 强制 (默认) 和 严格模式)。如 function fn(int $a){}【7.0+】
  18. 支持返回值类型声明。如声明返回类型为array: function fn(int $a): array【7.0+】
  19. 新增null合并运算符语法糖。如:$username = $_GET['user'] ?? 'nobody'; 【7.0+】
  20. 新增太空船操作符(组合比较符)。如:echo 1 <=> 1; // 0【7.0+】
  21. 生成器可以返回表达式。【7.0+】
  22. session_start() 可以接受一个 array 作为参数, 用来覆盖 php.ini 文件中设置的 会话配置选项。 【7.0+】
  23. 新增可使代码更简洁的 preg_replace_callback_array() 函数【7.0+】
  24. 允许在克隆表达式上访问对象成员,例如: (clone $foo)->bar()【7.0+】
  25. 新加入两个跨平台的函数:random_bytes() 和 random_int() 用来产生高安全级别的随机字符串和随机整数。【7.0+】
  26. 新增 IntlChar 类用于暴露出更多的 ICU 功能。这个类自身定义了许多静态方法用于操作多字符集的 unicode 字符。【7.0+】
  27. 放宽了保留词限制,允许全局保留词用于类/接口/Trait 中的属性、常量和方法名。 在引入新关键词时,此变更减少了对向后兼容的破坏,避免了 API 命名的限制。如:Project::new('Project Name')->private()->for('purpose here')->with('username here');// 之前是不可以的【7.0+】
  28. 可为空(Nullable)类型,参数以及返回值的类型现在可以通过在类型前加上一个问号使之允许为空。如:function fn(?string $name): ?string{}【7.1+】
  29. 新增返回值类型void。如:function swap(&$left, &$right) : void{}【7.1+】
  30. 短数组语法“[]”现在作为list()语法的一个备选项,可以用于将数组的值赋给一些变量(包括在foreach中)。如:[$id1, $name1] = $data[0]; foreach ($data as list($id, $name)) {}【7.1+】
  31. 新增支持设置类常量的可见性。如:public const A = 1;protected const B = 2;private const C = 3;【7.1+】
  32. 新引入 iterable 伪类 (与callable类似)。【7.1+】
  33. 新增多异常捕获处理语法糖。如:catch (FirstException | SecondException $e)【7.1+】
  34. 新增 list() 支持键名。如:list("id" => $id1, "name" => $name1) = $data[0];【7.1+】
  35. 新增支持为负的字符串偏移量。如:"abcdef"[-2];strpos("aabbcc", "b", -3);【7.1+】
  36. 新增 openssl 扩展支持 AEAD【7.1+】
  37. 新增 pcntl_async_signals() 信号处理函数。【7.1+】
  38. 新增 HTTP/2 server push support in ext/curl。【7.1+】
  39. 新增对象类型 object, 引进了可用于逆变(contravariant)参数输入和协变(covariant)返回任何对象类型。如:function fn(object $obj) : object{}【7.2+】
  40. 新增可通过名称加载扩展。【7.2+】
  41. 新增允许重写抽象方法(Abstract method) 【7.2+】
  42. 新增使用Argon2算法生成密码散列。【7.2+】
  43. 新增 PDO 扩展字符串扩展类型。【7.2+】
  44. 新增 LDAP 扩展支持新的操作方式。【7.2+】
  45. sockets 扩展添加了地址信息。【7.2+】
  46. 支持允许分组命名空间的尾部逗号。如:use Foo\Bar\{Foo,Bar,Baz,};【7.2+】

主要不兼容函数列表

函数名备注
ldap_sort()7.0.0+已移除
xml_set_object()7.0.0+为了避免内存泄露,该函数在执行结束时需要手动清除 $parse
shmop_open()7.0.0+现在返回一个资源而非一个int
exec() & system() & passthru()7.0.0+对 NULL 增加了保护
setlocale()7.0.0+不再接受 category 传入字符串。 应当使用 LC_* 常量
preg_replace()7.0.0+不再支持 "e" (PREG_REPLACE_EVAL). 应当使用 preg_replace_callback() 替代
mktime() & gmmktime()7.0.0+不再接受 is_dst 参数
imagepsbbox()7.0.0+已移除
imagepsencodefont()7.0.0+已移除
imagepsextendfont()7.0.0+已移除
imagepsfreefont()7.0.0+已移除
imagepsloadfont()7.0.0+已移除
imagepsslantfont()7.0.0+已移除
imagepstext()7.0.0+已移除
dl()7.0.0+在PHP-FPM模式下已移除
set_magic_quotes_runtime()7.0.0+已移除
magic_quotes_runtime()7.0.0+已移除
set_socket_blocking()7.0.0+已移除
mcrypt_generic_end()7.0.0+已移除
mcrypt_ecb()7.0.0+已移除
mcrypt_cbc()7.0.0+已移除
mcrypt_cfb()7.0.0+已移除
mcrypt_ofb()7.0.0+已移除
call_user_method()7.0.0+已移除
call_user_method_array()7.0.0+已移除
ereg* 系列函数7.0.0+已移除,建议使用PCRE系列函数代替
__autoload()7.2.0+已移除
assert()7.2.0+废弃了字符串的 assert(),最好提供 bool 的表达式
png2wbmp() 和 jpeg2wbmp()7.2.0+已移除
create_function()7.2.0+已移除
parse_str()7.2.0+需要加第二个参数成为必选项
each()7.2.0+已移除
gmp_random()7.2.0+已移除
read_exif_data()7.2.0+已移除,使用 exif_read_data() 代替

其他主要不兼容点

  • 【5.6.x+】cURL 文件上传

必须先设置 CURLOPT_SAFE_UPLOAD 为 FALSE 才能够使用 @file 语法来上传文件。 建议使用 CURLFile 类来上传文件。

  • 【5.6.x+】更严格的 json_decode()

对于 JSON 字面量 true,false 和 null,如果不采用小写格式,将会被 json_decode() 函数拒绝, 同时相应的设置 json_last_error()。 在之前的版本中,json_decode() 函数可以接受这些字面量的 全部大写或者大小写混写的格式。

此变更仅会影响传入到 json_decode() 中的 JSON 格式无效的情况, 有效的 JSON 输入不会受到影响并且能够正确解析。

  • 【5.6.x+】使用数组标识符为类定义数组类型的属性时,数组的键不会被覆盖

在 PHP 5.6 之前的版本中,为类定义数组类型的属性时,如果数组中同时使用了显式数组键和隐式数组键,并且显式的键和隐式的序列键相同,那么数组的键将被覆盖。如:

<?php
class C {
    const ONE = 1;
    public $array = [
        self::ONE => 'foo',
        'bar',
        'quux',
    ];
}

var_dump((new C)->array);
  • 【5.6.x+】从不兼容的上下文调用方法

已废止从不兼容的上下文调用方法,并且产生 E_DEPRECATED 错误 (以前是 E_STRICT)。 在 PHP 的后续版本中可能彻底移除对此特性的支持。

  • 【5.6.x+】$HTTP_RAW_POST_DATA 和 always_populate_raw_post_data

使用 always_populate_raw_post_data 会导致在填充 $HTTP_RAW_POST_DATA 时产生 E_DEPRECATED 错误。 请使用 php://input 替代 $HTTP_RAW_POST_DATA, 因为它可能在后续的 PHP 版本中被移除。 设置 always_populate_raw_post_data 为 -1 (这样会强制 $HTTP_RAW_POST_DATA 未定义,所以也不回导致 E_DEPRECATED 的错误) 来体验新的行为。

  • 【5.6.x+】iconv 和 mbstring 编码设置

iconv 和 mbstring 配置选项中 和编码相关的选项都已废弃, 请使用 default_charset。 废弃的选项有:

iconv.input_encoding
iconv.output_encoding
iconv.internal_encoding
mbstring.http_input
mbstring.http_output
mbstring.internal_encoding
  • 【7.0.x+】错误和异常处理相关的变更

在 PHP 7 中,很多致命错误以及可恢复的致命错误,都被转换为异常来处理了。 这些异常继承自 Error 类,此类实现了 Throwable 接口 (所有异常都实现了这个基础接口)。

这也意味着,当发生错误的时候,以前代码中的一些错误处理的代码将无法被触发。 因为在 PHP 7 版本中,已经使用抛出异常的错误处理机制了。 (如果代码中没有捕获 Error 异常,那么会引发致命错误)。

1) set_exception_handler() 不再保证收到的一定是 Exception 对象:
抛出 Error 对象时,如果 set_exception_handler() 里的异常处理代码声明了类型 Exception ,将会导致 fatal error。

想要异常处理器同时支持 PHP5 和 PHP7,应该删掉异常处理器里的类型声明。如果代码仅仅是升级到 PHP7,则可以把类型 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) { ... }

2) 当内部构造器失败的时候,总是抛出异常:
在之前版本中,如果内部类的构造器出错,会返回 NULL 或者一个不可用的对象。 从 PHP 7 开始,如果内部类构造器发生错误, 那么会抛出异常。

3) 解析错误会抛出 ParseError 异常:
解析错误会抛出 ParseError 异常。 对于 eval() 函数,需要将其包含到一个 catch 代码块中来处理解析错误。

4) E_STRICT 警告级别变更:
原有的 E_STRICT 警告都被迁移到其他级别。 E_STRICT 常量会被保留,所以调用 error_reporting(E_ALL|E_STRICT) 不会引发错误。

场景新的级别/行为
将资源类型的变量用作键来进行索引E_NOTICE
抽象静态方法不再警告,会引发错误
重复定义构造器函数不再警告,会引发错误
在继承的时候,方法签名不匹配E_WARNING
在两个 trait 中包含相同的(兼容的)属性不再警告,会引发错误
以非静态调用的方式访问静态属性E_NOTICE
变量应该以引用的方式赋值E_NOTICE
变量应该以引用的方式传递(到函数参数中)E_NOTICE
以静态方式调用实例方法E_DEPRECATED
  • 【7.0.x+】关于变量处理的变化

PHP 7 现在使用了抽象语法树来解析源代码。这为语言带来了许多改进,由于之前的 PHP 的解释器的限制所不可能实现的,但出于一致性的原因导致了一些特殊例子的变动,而这些变动打破了向后兼容。

1) 关于间接使用变量、属性和方法的变化:
对变量、属性和方法的间接调用现在将严格遵循从左到右的顺序来解析,而不是之前的混杂着几个特殊案例的情况。 下面这张表说明了这个解析顺序的变化。

表达式PHP 5 的解析方式PHP 7 的解析方式
$$foo'bar'${$foo'bar'}($$foo)'bar'
$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']()

2) list() 不再以反向的顺序来进行赋值:
list() 现在会按照变量定义的顺序来给他们进行赋值,而非反过来的顺序。 通常来说,这只会影响list() 与数组的[]操作符一起使用的案例,如下所示:

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

3) 空的list()赋值支持已经被移除:
list() 结构现在不再能是空的。如下的例子不再被允许:

<?php
list() = $a;
list(,,) = $a;
list($x, list(), $y) = $a;

4) list()不再能解开string:
list() 不再能解开字符串(string)变量。可以使用str_split()来代替。

5) global 只接受简单变量:
可变变量不再能够与 global 关键字一起使用。 如果需要的话可以使用圆括号来模拟之前的行为。

<?php
function f() {
    // Valid in PHP 5 only.
    global $$foo->bar;

    // Valid in PHP 5 and 7.
    global ${$foo->bar};
}

作为一个通用的准则,global 一个除了裸的变量以外的任何东西都是不被推荐的。

  • 【7.0.x+】foreach的变化

【7.0.x+】foreach发生了细微的变化,控制结构, 主要围绕阵列的内部数组指针和迭代处理的修改。

1) foreach不再改变内部数组指针:
在PHP7之前,当数组通过 foreach 迭代时,数组指针会移动。现在开始,不再如此,如:

$array = [0, 1, 2];
foreach ($array as &$val) 
{
    var_dump(current($array));
}
// php7 下会打印3次:int(0),而 php5 会打印:int(0), int(1), int(2)

2) foreach 通过值遍历时,操作的值为数组的副本:
当默认使用通过值遍历数组时,foreach 实际操作的是数组的迭代副本,而非数组本身。这就意味着,foreach 中的操作不会修改原数组的值。

3) foreach通过引用遍历时,有更好的迭代特性:
当使用引用遍历数组时,现在 foreach 在迭代中能更好的跟踪变化。例如,在迭代中添加一个迭代值到数组中,如:

$array = [0];
foreach ($array as &$val) {
    var_dump($val);
    $array[1] = 1;
}
// php5 输出 int(0),php7 输出:int(0), int(1)

4) 非Traversable 对象的遍历:
迭代一个非Traversable对象将会与迭代一个引用数组的行为相同。 这将导致在对象添加或删除属性时,foreach通过引用遍历时,有更好的迭代特性也能被应用

  • 【7.0.x+】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
  • 【7.0.x+】无效的类、接口以及 trait 命名
    不能以下列名字来命名类、接口以及 trait:
bool
int
float
string
NULL
TRUE
FALSE

此外,也不要使用下列的名字来命名类、接口以及 trait。虽然在 PHP 7.0 中, 这并不会引发错误, 但是这些名字是保留给将来使用的。

resource
object
mixed
numeric
  • 【7.0.x+】移除了 ASP 和 script PHP 标签

使用类似 ASP 的标签,以及 script 标签来区分 PHP 代码的方式被移除。受到影响的标签有:

<% %>
<%= %>
<script language="php"> </script>
  • 【7.0.x+】string处理上的调整

十六进制字符串不再被认为是数字。如:is_numeric("0x123"); // false

  • 【7.0.x+】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;

可以通过使用括号来消除歧义。

  • 【7.0.x+】函数定义不可以包含多个同名参数

在函数定义中,不可以包含两个或多个同名的参数。 例如,下面代码中的函数定义会触发 E_COMPILE_ERROR 错误:

<?php
function foo($a, $b, $unused, $unused) {
    //
}
  • 【7.0.x+】Switch 语句不可以包含多个 default 块

在 switch 语句中,两个或者多个 default 块的代码已经不再被支持。 例如,下面代码中的 switch 语句会触发 E_COMPILE_ERROR 错误:

<?php
switch (1) {
    default:
    break;
    default:
    break;
}
  • 【7.0.x+】在函数中检视参数值会返回当前的值

当在函数代码中使用 func_get_arg() 或 func_get_args() 函数来检视参数值, 或者使用 debug_backtrace() 函数查看回溯跟踪, 以及在异常回溯中所报告的参数值是指参数当前的值(有可能是已经被函数内的代码改变过的值), 而不再是参数被传入函数时候的原始值了。

<?php
function foo($x) {
    $x++;
    var_dump(func_get_arg(0));
}
foo(1);?>
// php5 -> 1; php7 -> 2
  • 【7.0.x+】$HTTP_RAW_POST_DATA 被移除

不再提供 $HTTP_RAW_POST_DATA 变量。 使用 php://input 作为替代。

  • 【7.0.x+】INI 文件中 # 注释格式被移除

在 INI 文件中,不再支持以 # 开始的注释行,使用 ;(分号)来表示注释。此变更适用于 php.ini 以及用 parse_ini_file() 和 parse_ini_string() 函数来处理的文件。

  • 【7.0.x+】JSON 扩展已经被 JSOND 取代

JSON 扩展已经被 JSOND 扩展取代。 对于数值的处理,有以下两点需要注意的: 第一,数值不能以点号(.)结束 (例如,数值 34. 必须写作 34.0 或 34)。 第二,如果使用科学计数法表示数值,e 前面必须不是点号(.) (例如,3.e3 必须写作 3.0e3 或 3e3)。 另外,空字符串不再被视作有效的 JSON 字符串。

  • 【7.0.x+】在数值溢出的时候,内部函数将会失败

将浮点数转换为整数的时候,如果浮点数值太大,导致无法以整数表达的情况下, 在之前的版本中,内部函数会直接将整数截断,并不会引发错误。 在 PHP 7.0 中,如果发生这种情况,会引发 E_WARNING 错误,并且返回 NULL。

  • 【7.0.x+】自定义会话处理器的返回值修复

在自定义会话处理器中,如果函数的返回值不是 FALSE,也不是 -1, 会引发致命错误。现在,如果这些函数的返回值不是布尔值,也不是 -1 或者 0,函数调用结果将被视为失败,并且引发 E_WARNING 错误。

  • 【7.0.x+】相等的元素在排序时的顺序问题

由于内部排序算法进行了提升, 可能会导致对比时被视为相等的多个元素之间的顺序不稳定。

Note:
在对比时被视为相等的多个元素之间的排序顺序是不可信赖的,即使是相等的两个元素, 他们的位置也可能被排序算法所改变。

  • 【7.0.x+】PHP4 风格的构造函数

PHP4 风格的构造函数(方法名和类名一样)将被弃用,并在将来移除。 如果在类中仅使用了 PHP4 风格的构造函数,PHP7 会产生 E_DEPRECATED 警告。 如果还定义了 __construct() 方法则不受影响。

  • 【7.0.x+】静态调用非静态的方法

废弃了静态(Static)调用未声明成 static 的方法,未来可能会彻底移除该功能。

  • 【7.0.x+】password_hash() 盐值选项

废弃了 password_hash() 函数中的盐值选项,阻止开发者生成自己的盐值(通常更不安全)。 开发者不传该值时,该函数自己会生成密码学安全的盐值。因此再无必要传入自己自定义的盐值。

  • 【7.0.x+】capture_session_meta SSL 上下文选项

废弃了 capture_session_meta 内的 SSL 上下文选项。 现在可以通过 stream_get_meta_data() 获取 SSL 元数据(metadata)。

  • 【7.1.x+】当传递参数过少时将抛出错误

在过去如果我们调用一个用户定义的函数时,提供的参数不足,那么将会产生一个警告(warning)。 现在,这个警告被提升为一个错误异常(Error exception)。这个变更仅对用户定义的函数生效, 并不包含内置函数。

  • 【7.1.x+】call_user_func()不再支持对传址的函数的调用

call_user_func() 现在在调用一个以引用作为参数的函数时将始终失败。

  • 【7.1.x+】ini选项移除
    移除了以下ini选项:
session.entropy_file
session.entropy_length
session.hash_function
session.hash_bits_per_character
  • 【7.1.x+】mcrypt扩展

mcrypt 扩展已经过时了大约10年,并且用起来很复杂。因此它被废弃并且被 OpenSSL 所取代。 从PHP 7.2起它将被从核心代码中移除并且移到PECL中。

  • 【7.1.x+】mb_ereg_replace()和mb_eregi_replace()的Eval选项

对于mb_ereg_replace()和mb_eregi_replace()的 e模式修饰符现在已被废弃。

  • 【7.1.x+】不带引号的字符串

不带引号的字符串是不存在的全局常量,转化成他们自身的字符串。 在以前,该行为会产生 E_NOTICE,但现在会产生 E_WARNING。在下一个 PHP 主版本中,将抛出 Error 异常。

  • 【7.1.x+】禁止对自我检查范围的函数进行动态调用

涉及的函数有:

assert() - with a string as the first argument
compact()
extract()
func_get_args()
func_get_arg()
func_num_args()
get_defined_vars()
mb_parse_str() - with one arg
parse_str() - with one arg
<?php
(function () {
    'func_num_args'();  // Warning: Cannot call func_num_args() dynamically in %s on line %d
})();

兼容性检测工具

PHP7 兼容性检测工具 php7cc

https://github.com/sstalle/php7cc