公司项目将从PHP5.5升级到PHP7.2, 正好抽空做下深入的学习.
升级到7.2后可用的主要新特性
支持使用表达式定义常量。如:
const TWO = ONE * 2;
【5.6+】新增语法糖:使用
...
运算符定义变长参数函数。如:function fn($a, $b = null, ...$params) {}
【5.6+】新增语法糖:使用
...
运算符进行参数展开。类似 Ruby 中的连接运算符特性。【5.6+】新增使用
**
进行幂运算。如:printf("2 ** 3 == %d\n", 2 ** 3);
【5.6+】扩展
use
运算符用以支持在类中导入外部的函数和常量。【5.6+】SAPI
模块中实现了一个交互式调试器phpdbg。【5.6+】支持
php://input
可以多次打开并读取。【5.6+】支持大文件(大于 2GB)上传。【5.6+】
GMP
支持运算符重载。【5.6+】新加
hash_equals()
比较字符串函数可避免时序攻击。【5.6+】新增加
__debugInfo()
,当使用var_dump()
输出对象的时候, 可以用来控制要输出的属性和值。【5.6+】新增
gost-crypto
散列算法。【5.6+】对
SSL/TLS
的支持进行了大幅度的提升。【5.6+】支持通过
define()
定义常量数组 【7.0+】支持通过
new class
来实例化一个匿名类,这可以用来替代一些“用后即焚”的完整类定义。【7.0+】新增的函数
intdiv()
用来进行整数的除法运算。 【7.0+】支持标量类型声明(有两种模式: 强制 (默认) 和 严格模式)。如
function fn(int $a){}
【7.0+】支持返回值类型声明。如声明返回类型为array:
function fn(int $a): array
【7.0+】新增null合并运算符语法糖。如:
$username = $_GET['user'] ?? 'nobody';
【7.0+】新增太空船操作符(组合比较符)。如:
echo 1 <=> 1; // 0
【7.0+】生成器可以返回表达式。【7.0+】
session_start()
可以接受一个array
作为参数, 用来覆盖php.ini
文件中设置的 会话配置选项。 【7.0+】新增可使代码更简洁的
preg_replace_callback_array()
函数【7.0+】允许在克隆表达式上访问对象成员,例如:
(clone $foo)->bar()
【7.0+】新加入两个跨平台的函数:
random_bytes()
和random_int()
用来产生高安全级别的随机字符串和随机整数。【7.0+】新增
IntlChar
类用于暴露出更多的ICU
功能。这个类自身定义了许多静态方法用于操作多字符集的unicode
字符。【7.0+】放宽了保留词限制,允许全局保留词用于类/接口/Trait 中的属性、常量和方法名。 在引入新关键词时,此变更减少了对向后兼容的破坏,避免了 API 命名的限制。
如:Project::new('Project Name')->private()->for('purpose here')->with('username here');// 之前是不可以的
【7.0+】可为空(Nullable)类型,参数以及返回值的类型现在可以通过在类型前加上一个问号使之允许为空。
如:function fn(?string $name): ?string{}
【7.1+】新增返回值类型void。如:
function swap(&$left, &$right) : void{}
【7.1+】短数组语法“[]”现在作为list()语法的一个备选项,可以用于将数组的值赋给一些变量(包括在foreach中)。
如:[$id1, $name1] = $data[0]; foreach ($data as list($id, $name)) {}
【7.1+】新增支持设置类常量的可见性。如:
public const A = 1;protected const B = 2;private const C = 3;
【7.1+】新引入
iterable
伪类 (与callable类似)。【7.1+】新增多异常捕获处理语法糖。如:
catch (FirstException | SecondException $e)
【7.1+】新增
list()
支持键名。如:list("id" => $id1, "name" => $name1) = $data[0];
【7.1+】新增支持为负的字符串偏移量。如:
"abcdef"[-2];strpos("aabbcc", "b", -3);
【7.1+】新增
openssl
扩展支持AEAD
【7.1+】新增
pcntl_async_signals()
信号处理函数。【7.1+】新增
HTTP/2 server push support in ext/curl
。【7.1+】新增对象类型
object
, 引进了可用于逆变(contravariant)
参数输入和协变(covariant)
返回任何对象类型。
如:function fn(object $obj) : object{}
【7.2+】新增可通过名称加载扩展。【7.2+】
新增允许重写抽象方法(
Abstract method
) 【7.2+】新增使用
Argon2
算法生成密码散列。【7.2+】新增
PDO
扩展字符串扩展类型。【7.2+】新增
LDAP
扩展支持新的操作方式。【7.2+】sockets
扩展添加了地址信息。【7.2+】支持允许分组命名空间的尾部逗号。如:
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 之前的版本中,为类定义数组类型的属性时,如果数组中同时使用了显式数组键和隐式数组键,并且显式的键和隐式的序列键相同,那么数组的键将被覆盖。如:
1 |
|
- 【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
。 废弃的选项有:
1 | iconv.input_encoding |
- 【7.0.x+】错误和异常处理相关的变更
在 PHP 7 中,很多致命错误以及可恢复的致命错误,都被转换为异常来处理了。 这些异常继承自 Error
类,此类实现了 Throwable
接口 (所有异常都实现了这个基础接口)。
这也意味着,当发生错误的时候,以前代码中的一些错误处理的代码将无法被触发。 因为在 PHP 7 版本中,已经使用抛出异常的错误处理机制了。 (如果代码中没有捕获 Error 异常,那么会引发致命错误)。
set_exception_handler()
不再保证收到的一定是Exception
对象:
抛出 Error
对象时,如果 set_exception_handler()
里的异常处理代码声明了类型 Exception
,将会导致 fatal error
。
想要异常处理器同时支持 PHP5 和 PHP7,应该删掉异常处理器里的类型声明。如果代码仅仅是升级到 PHP7,则可以把类型 Exception
替换成 Throwable
。
1 |
|
当内部构造器失败的时候,总是抛出异常
:
在之前版本中,如果内部类的构造器出错,会返回 NULL 或者一个不可用的对象。 从 PHP 7 开始,如果内部类构造器发生错误, 那么会抛出异常。
解析错误会抛出 ParseError 异常
:
解析错误会抛出 ParseError
异常。 对于 eval()
函数,需要将其包含到一个 catch
代码块中来处理解析错误。
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 的解释器的限制所不可能实现的但出于一致性的原因导致了一些特殊例子的变动,而这些变动打破了向后兼容。
关于间接使用变量、属性和方法的变化
:
对变量、属性和方法的间接调用现在将严格遵循从左到右的顺序来解析,而不是之前的混杂着几个特殊案例的情况。 下面这张表说明了这个解析顺序的变化。
表达式 | PHP5的解析方式 | PHP7的解析方式 |
---|---|---|
$$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']() |
list() 不再以反向的顺序来进行赋值
:
list() 现在会按照变量定义的顺序来给他们进行赋值,而非反过来的顺序。 通常来说,这只会影响list() 与数组的[]操作符一起使用的案例,如下所示:
1 |
|
空的list()赋值支持已经被移除
:
list() 结构现在不再能是空的。如下的例子不再被允许:
1 |
|
list()不再能解开string
:
list() 不再能解开字符串(string)变量。可以使用str_split()来代替。
global 只接受简单变量
:
可变变量不再能够与 global 关键字一起使用。 如果需要的话可以使用圆括号来模拟之前的行为。
1 |
|
作为一个通用的准则,global 一个除了裸的变量以外的任何东西都是不被推荐的。
- 【7.0.x+】foreach的变化
【7.0.x+】foreach发生了细微的变化,控制结构, 主要围绕阵列的内部数组指针和迭代处理的修改。
foreach不再改变内部数组指针
:
在PHP7之前,当数组通过 foreach 迭代时,数组指针会移动。现在开始,不再如此,如:
1 | $array = [0, 1, 2]; |
foreach 通过值遍历时,操作的值为数组的副本
:
当默认使用通过值遍历数组时,foreach 实际操作的是数组的迭代副本,而非数组本身。这就意味着,foreach 中的操作不会修改原数组的值。
foreach通过引用遍历时,有更好的迭代特性:
当使用引用遍历数组时,现在 foreach 在迭代中能更好的跟踪变化。例如,在迭代中添加一个迭代值到数组中,如:
1 |
|
非Traversable 对象的遍历
:
迭代一个非Traversable对象将会与迭代一个引用数组的行为相同。 这将导致在对象添加或删除属性时,foreach通过引用遍历时,有更好的迭代特性也能被应用
- 【7.0.x+】new 操作符创建的对象不能以引用方式赋值给变量
new 语句创建的对象不能 以引用的方式赋值给变量。
1 |
|
- 【7.0.x+】无效的类、接口以及 trait 命名
不能以下列名字来命名类、接口以及 trait:
1 | bool |
此外,也不要使用下列的名字来命名类、接口以及 trait。虽然在 PHP 7.0 中, 这并不会引发错误, 但是这些名字是保留给将来使用的。
1 | resource |
- 【7.0.x+】移除了 ASP 和 script PHP 标签
使用类似 ASP 的标签,以及 script 标签来区分 PHP 代码的方式被移除。受到影响的标签有:
1 | <% %> |
- 【7.0.x+】string处理上的调整
十六进制字符串不再被认为是数字。如:is_numeric("0x123"); // false
- 【7.0.x+】yield 变更为右联接运算符
在使用 yield 关键字的时候,不再需要括号, 并且它变更为右联接操作符,其运算符优先级介于 print 和 => 之间。 这可能导致现有代码的行为发生改变:
1 |
|
可以通过使用括号来消除歧义
- 【7.0.x+】函数定义不可以包含多个同名参数
在函数定义中,不可以包含两个或多个同名的参数。 例如,下面代码中的函数定义会触发 E_COMPILE_ERROR
错误:
1 |
|
- 【7.0.x+】Switch 语句不可以包含多个 default 块
在 switch 语句中,两个或者多个 default 块的代码已经不再被支持。 例如,下面代码中的 switch 语句会触发 E_COMPILE_ERROR
错误:
1 |
|
- 【7.0.x+】在函数中检视参数值会返回当前的值
当在函数代码中使用 func_get_arg()
或 func_get_args()
函数来检视参数值, 或者使用 debug_backtrace()
函数查看回溯跟踪, 以及在异常回溯中所报告的参数值是指参数当前的值(有可能是已经被函数内的代码改变过的值), 而不再是参数被传入函数时候的原始值了。
1 |
|
- 【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+】相等的元素在排序时的顺序问题
由于内部排序算法进行了提升, 可能会导致对比时被视为相等的多个元素之间的顺序不稳定。
在对比时被视为相等的多个元素之间的排序顺序是不可信赖的,即使是相等的两个元素, 他们的位置也可能被排序算法所改变。
- 【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选项:
1 | session.entropy_file |
- 【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+】禁止对自我检查范围的函数进行动态调用
涉及的函数有:
1 | assert() - with a string as the first argument |
1 |
|