本文基于的PHP8 commit
为:14806e0824ecd598df74cac855868422e44aea53
有如下代码:
1 |
|
对应的opcode
为:
1 | L3 #0 ECHO 6 |
我们可以分析出,这个echo
表达式对应的AST
大概如下:
1 | ZEND_ECHO |
所以,可以看到,PHP
代码生成的时候,很轻松的进行优化了:
1 | ZEND_ECHO |
最后就会优化为:
1 | ZEND_ECHO |
所以生成的opcode
只有一条。
那么,我们再来看一个PHP
目前没有优化的例子:
1 |
|
对应的opcode
如下:
1 | L3 #0 ASSIGN $x 1 |
可以看到,这里没有进行优化,理论上来说,对常量进行折叠的话,可以减少一条opcode
。那么为什么PHP
内核它没有对这种情况进行优化呢?我们先来看一看这条语句对应的AST
:
1 | ZEND_ECHO |
可以发现,如果对AST
进行深度遍历的话,是先进行x + 2
,而x
是一个变量,折叠不了,所以就没有优化到了,具体的代码是这样的(在函数zend_compile_binary_op
里面):
1 | if (left_node.op_type == IS_CONST && right_node.op_type == IS_CONST) { |
我们发现,折叠的情况只有是当左右节点都为IS_CONST
类型的时候,才会生效。
那么,面对这种情况,理论上我们可以怎么解决呢?我们可以对这个AST
进行旋转,得到:
1 | ZEND_ECHO |
然后,我们就可以优化为:
1 | ZEND_ECHO |
既然,PHP
没有做这方面的优化工作,那么,我们写代码的时候,就可以稍微注意一下了。常量尽可能的往左边靠拢,例如1 + 2 + x
这样。
后续我们的yaphp
会使用LLVM
来对这方面进行优化。