php 7中,首先进行词法分析,将源代码切割为多个字符串单元,分割后的字符串称为Token。而一个一个独立的Token是无法表达完整语义的,需经过语法分析阶段,将Token转换为抽象语法树(简称AST)。之后,抽象语法树被转换为机器指令执行。在PHP中,这些指令称为opcode
第一步: 源码通过词法分析得到Token
第二步:基于语法分析器生成抽象语法树(AST)
第三步: 抽象语法树转换为opcodes(opcode
指令集合),PHP解析执行opcodes
PHP7运转的初步理解
这段代码首先会被切割为token
- 开始->
- Scanning(Lexing),将PHP语言转换为语言片段Token->
- Parsing,将Token转换为抽象语法树->
- Compilation将语法树转换为Opcodes->
- Excution一次执行Opcodes
PHP提供了token_get_all()函数来获取PHP代码被切割后的Token
<?php
$lan = '<?php $a = 1; echo $a';
$tokens = token_get_all($lan);
foreach ($tokens as $token) {
if (is_array($token)) {
echo "Line {$token[2]}: ", token_name($token[0]), " ('{$token[1]}')", PHP_EOL;
}
}
打印结果
Line 1: T_OPEN_TAG ('<?php ')
Line 1: T_VARIABLE ('$a')
Line 1: T_WHITESPACE (' ')
Line 1: T_WHITESPACE (' ')
Line 1: T_LNUMBER ('1')
Line 1: T_WHITESPACE (' ')
Line 1: T_ECHO ('echo')
Line 1: T_WHITESPACE (' ')
Line 1: T_VARIABLE ('$a')
AST抽象语法树的支持,实现了PHP编译器和解释器解耦,有效提升了可维护性
抽象语法树具有树状结构
AST(抽象语法树)的编译是生成指令集opcode的过程,词法和语法分析后生成的AST会保存在CG(ast)中,然后zend虚拟机会将AST进一步转换为zend_op_array,以便在虚拟机中执行
在遍历之前,需要先初始化指令集op_array,用来存放指令,通过调用函数init_op_array对op_array 进行初始化
php5的
PHP7 的内核中有一个重要的变化是加入了 AST。在 PHP5中,从 php 脚本到 opcodes 的执行的过程是:
- Lexing:词法扫描分析,将源文件转换成 token 流;
- Parsing:语法分析,在此阶段生成 op arrays。
PHP7 中在语法分析阶段不再直接生成 op arrays,而是先生成 AST,所以过程多了一步:
- Lexing:词法扫描分析,将源文件转换成 token 流;
- Parsing:语法分析,从 token 流生成抽象语法树;
- Compilation:从抽象语法树生成 op arrays。
PHP7性能提升原因总结:
1、存储变量的结构体变小,尽量使结构体里成员共用内存空间,减少引用,这样内存占用降低,变量的操作速度得到提升。
2、字符串结构体的改变,字符串信息和数据本身原来是分成两个独立内存块存放,php7尽量将它们存入同一块内存,提升了cpu缓存命中率。
3、数组结构的改变,数组元素和hash映射表在php5中会存入多个内存块,php7尽量将它们分配在同一块内存里,降低了内存占用、提升了cpu缓存命中率。
4、改进了函数的调用机制,通过对参数传递环节的优化,减少一些指令操作,提高了执行效率。