PHP7都发布好几年了,你确定不了解一下?
PHP7
新特性语法
标量类型声明
1 | // 强制模式 |
强制模式(默认,既强制类型转换)下还是会对不符合预期的参数进行强制类型转换,
严格模式下则触发TypeError
的致命错误。
返回值类型声明
1 | function arraysSum(array ...$arrays): array |
NULL
合并运算符: ??
由于日常使用中存在大量同时使用三元表达式
和 isset()
的情况,
NULL 合并运算符使得变量存在且值不为NULL, 它就会返回自身的值,否则返回它的第二个操作数。
1 | // 如果 $_GET['user'] 不存在返回 'nobody',否则返回 $_GET['user'] 的值 |
太空船操作符(组合比较符)
太空船操作符用于比较两个表达式。当$a
大于、等于或小于$b
时它分别返回-1、0或1
。
1 | // 整型 |
通过 define()
定义常量数组
1 | define('ANIMALS', [ |
匿名类
现在支持通过new class
来实例化一个匿名类,实例如下:
1 | interface Logger { |
Unicode codepoint
转译语法
这接受一个以16进制形式的 Unicode codepoint
,并打印出一个双引号或heredoc
包围的 UTF-8
编码格式的字符串。
可以接受任何有效的 codepoint
,并且开头的 0 是可以省略的。
1 | echo "\u{aa}"; |
Closure::call()
Closure::call()
现在有着更好的性能,简短干练的暂时绑定一个方法到对象上闭包并调用它。
1 | class A {private $x = 1;} |
为unserialize()
提供过滤
这个特性旨在提供更安全的方式解包不可靠的数据。它通过白名单的方式来防止潜在的代码注入。
1 | // 转换对象为 __PHP_Incomplete_Class 对象 |
use
加强
从同一 namespace
导入的类、函数和常量现在可以通过单个 use 语句 一次性导入了。
1 | // PHP 7 之前版本用法 |
Generator
加强
增强了Generator
的功能,这个可以实现很多先进的特性
1 | function gen() |
整除 intdiv
新增了整除函数 intdiv()
,使用实例:
1 | var_dump(intdiv(10, 3)); //int(3) |
PHP7
废弃特性
PHP4
风格的构造函数
在 PHP4 中类中的函数可以与类名同名,这一特性在 PHP7 中被废弃,同时会发出一个 E_DEPRECATED 错误。当方法名与类名相同,且类不在命名空间中,
同时PHP5的构造函数(__construct)不存在时,会产生一个 E_DEPRECATED
错误。
1 | class A { |
以静态的方式调用非静态方法
以静态的方式调用非静态方法,不再支持:
1 | class A { |
password_hash()
随机因子选项
函数原 salt
量不再需要由开发者提供了。函数内部默认带有 salt
能力,无需开发者提供 salt
值。
capture_session_meta
SSL 上下文选项
废弃了 "capture_session_meta"
SSL 上下文选项。
在流资源上活动的加密相关的元数据可以通过 stream_get_meta_data()
的返回值访问。
PHP7移除的扩展
ereg
mssql
mysql
sybase_ct
PHP7
: 再深入一点~~
PHP7引擎( What will be in PHP 7 / PHPNG )
Performance Improvements with the addition of PHPNG engine
.(使用PHPNG引擎来提升性能)PHPNG
不再使用zval的二级指针。大多数出现的zval*变量和参数都将改变成zval。相应的,使用在这些变量上的宏Z_PP()也需要变成Z_P()。More
-> https://wiki.php.net/phpng-upgradingJIT - Just in Time compiler
即时编译 (参考百度百科介绍)Abstract Syntax Tree for compilation
(抽象语法树编译)Asynchronous refactoring of the I/O layer.
对I/O层的异步重构Multi-threaded build in Web Server
多线程构建Web服务器Expanded use of ->, [], (), {}, and :: operators
扩展使用 ->, [], (), {}, 和 :: 符号100% increase in performance
性能提升 100% (应该是QPS)Cool Name
: PHPNG 酷名:PHPNG引擎
Zval
的改变
PHP的各种类型的变量,其实,真正存储的载体就是Zval,它特点是海纳百川,有容乃大。从本质上看,它是C语言实现的一个结构体(struct)。
对于写PHP的同学,可以将它粗略理解为是一个类似array数组的东西。
PHP5
的Zval
,内存占据24
个字节,PHP7
的Zval
,内存占据16
个字节。
不需要引用的类型:NULL、Boolean、Long、Double
需要引用的类型:String、Array、Object、Resource、Reference
内部类型zend_string
Zend_string
是实际存储字符串的结构体,实际的内容会存储在val
(char,字符型)中,
而val
是一个char
数组,长度为1(方便成员变量占位)。
PHP数组的变化(HashTable
和Zend Array
)
在编写PHP程序过程中,使用最频繁的类型莫过于数组,PHP5的数组采用HashTable实现。
如果用比较粗略的概括方式来说,它算是一个支持双向链表的HashTable,不仅支持通过数组的key来做hash映射访问元素,也能通过foreach以访问双向链表的方式遍历数组元素。当我们通过key值访问一个元素内容的时候,有时需要3次的指针跳跃才能找对需要的内容。
而最重要的一点,就在于这些数组元素存储,都是分散在各个不同的内存区域的。
同理可得,在CPU读取的时候,因为它们就很可能不在同一级缓存中,会导致CPU不得不到下级缓存甚至内存区域查找,
也就是引起CPU缓存命中下降,进而增加更多的耗时。新版本的数组结构,非常简洁,让人眼前一亮。
最大的特点是,整块的数组元素和hash映射表全部连接在一起,被分配在同一块内存内。
如果是遍历一个整型的简单类型数组,效率会非常快,因为,数组元素(Bucket)本身是连续分配在同一块内存里,
并且,数组元素的zval会把整型元素存储在内部,也不再有指针外链,全部数据都存储在当前内存区域内。
当然,最重要的是,它能够避免CPU Cache Miss(CPU缓存命中率下降)。
Zend Array
的变化:
- 数组的value默认为zval。
- HashTable的大小从72下降到56字节,减少22%。
- Buckets的大小从72下降到32字节,减少50%。
- 数组元素的Buckets的内存空间是一同分配的。
- 数组元素的key(Bucket.key)指向zend_string。
- 数组元素的value被嵌入到Bucket中。
- 降低CPU Cache Miss。
函数调用机制(Function Calling Convention
)
PHP7改进了函数的调用机制,通过优化参数传递的环节,减少了一些指令,提高执行效率。
通过宏定义和内联函数(inline
),让编译器提前完成部分工作
PHP7
在这方面做了不少的优化,将不少需要在运行阶段要执行的工作,放到了编译阶段。
例如参数类型的判断(Parameters Parsing
),
因为这里涉及的都是固定的字符常量,因此,可以放到到编译阶段来完成,进而提升后续的执行效率。
AST
(Abstract Syntax Tree
,抽象语法树)
AST在PHP编译过程作为一个中间件的角色,替换原来直接从解释器吐出opcode的方式,
让解释器(parser)和编译器(compliler)解耦,可以减少一些Hack代码,同时,让实现更容易理解和可维护。
TLS
(Native Thread local storage
,原生线程本地存储)
PHP在多线程模式下(例如,Web服务器Apache的woker和event模式,就是多线程),
需要解决“线程安全”(TS,Thread Safe)的问题,因为线程是共享进程的内存空间的,
所以每个线程本身需要通过某种方式,构建私有的空间来保存自己的私有数据,避免和其他线程相互污染。
而PHP5采用的方式,就是维护一个全局大数组,为每一个线程分配一份独立的存储空间,
线程通过各自拥有的key值来访问这个全局数据组。而这个独有的key值在PHP5中需要传递给每一个需要用到全局变量的函数,
PHP7认为这种传递的方式并不友好,并且存在一些问题。
因而,尝试采用一个全局的线程特定变量来保存这个key值。