谈谈PHP5和PHP7的区别
PHP7对Zend引擎做了深度的优化,性能比PHP5系列版本快了近5倍,同时降低了PHP对系统资源的占用。那么到底怎么优化的,这个咱也不知道,于是买了本书来看——《PHP内核剖析》,这里做个笔记吧;
抽象语法树
在之前的PHP版本中,PHP代码在语法解析阶段直接生成了ZendVM指令;这有啥问题呢?主要是这样使得编译器和执行器耦合在一起。你想啊,编译生成的指令只认这个执行器,你换了别的执行器,你就得改语法解析规则;同样的PHP语法变了,对应的执行指令没有变化,也得改语法解析规则;
PHP7中新增了抽象语法树,首先是将PHP7代码解析生成抽象语法树,然后将抽象语法树编译为ZendVM指令。这样PHP编译器和执行器隔离开来了,编译器不需要关心指令的生成规则,执行器根据自己的规则将抽象语法树编译为对应的指令,执行器同样不需要关心该指令的语法规则是什么,一切装换规则都在这棵树里面了。
Native TLS(线程局部存储)
PHP5.x中有很多变量需要在不同函数间共享,多线程情况下很难通过全局变量来实现,得考虑线程安全,为了适应这个情况,PHP提供了一个线程安全资源管理器,将全局资源进行线程隔离,不同线程之间互不干扰;那么你使用全局资源就需要先获取本线程的资源池,这个查找就费时间了,于是就想着通过传参的方式把本线程的资源池传递给其它调用的函数,避免重复查找,这种实现方式极易漏参也不优雅;于是PHP7使用Native TLS 来保存线程的资源池,简单的来讲就是通过_thread来标识一个全局变量,这样这个全局变量就是线程独享的了,不同线程的修改不会相互影响,相当于copy了一份;
可以约束函数参数和返回值类型
PHP7中可以指定函数参数和返回值的类型,举个栗子:
1 | function getAuthorPhp(string $name): array{ |
这个函数参数必须为字符串,返回值必须是数组,否则直接error;
zval结构的变化
zval是PHP变量的内部结构;zval中有个重要成员:refcount_gc,用来记录变量的引用计数,在PHP5.x中,这个是绑定在zavl中,而不是在具体的value中,这就导致变量复制时需要复制两个结构:zval和zvalue_value;PHP7将引用计数转移到了具体的value中,这样更合理。因为zval只是变量的载体,value才是真正的值;
异常处理
PHP5.x中很多操作都是爆出error错误,PHP7中将多数错误改为异常抛出,这样一来就通过try catch 捕捉到,举个栗子:
1 | try{ |
新的异常处理方式使得错误处理更加可控。
HashTable的变化
这是PHP中超级强大的array()类型的内部实现结构,也是内核中使用超频繁的一个结构,即函数符号表,类符号表,常量符号表等都是通过HashTable来实现的;PHP7中HashTable结构的大小从72byte减小到56byte,数组元素Bucket结构也从72byte减小到32byte。
执行器
execute_data,opline采用寄存器变量存储;执行器的调度函数execute_ex(),这个函数负责执行PHP代码编译生成的ZendVM指令。PHP5.x中,这两个变量是由execute_ex()通过参数传递给各指令的handler的,在PHP7中则是通过寄存器存储,避免传参导致的频繁出入栈操作,因为寄存器相比内存访问速度更快,这个优化使得PHP的性能提高了5%。
原文作者: ybphp
原文链接: https://www.ybphp.com/2020/01/12/谈谈PHP5和PHP7的区别/
版权声明: 转载请注明出处(必须保留原文作者署名原文链接)