grape
全部视频:https://segmentfault.com/a/11...
引入
在我们平常写PHP代码总是会用到while语句,那么我们有没有去考虑过while语句是怎么实现的呢?
我们来看下面的这段代码:
<?php
$a = 1;
while($a){
}
我们知道这段代码是个死循环,毋庸置疑,但是在PHP中,它是如何做到的呢?请看下文。
分析
首先,我们自己分析一下这个while语句,如果让我们来设计,我们会如何设计呢?笔者写出脑补几点:
- PHP是C语言编写的,直接去沿用C的语法,while套用。
- 在源码设计中加入goto语句。
- for循环嵌套if语句
- 等等(大家可以头脑风暴下)
接下来我们看一下PHP源码中是如何实现的。
俗话说,实践是检验真理的唯一道路,那么我们就去gdb一下,调试上边的代码,用事实说话。
接下来是gdb的过程,因为是ast树的构建过程,之前文章已经详细解释过,此处不再赘述,文章传送门:2019-05-07 发布【PHP源码学习】2019-03-21 AST,gdb过程如图1所示:
此时我们可以知道AST就是长的图二的样子,如图2:
ast树建立好了,但是他执行了什么指令,我们还是得去看看他的opcode是什么,继续gdb代码,执行到zend_file_context_end之后,此时opcode已经执行完成,我们打印下gdb结果,如图3所示:
ps:在图三中我们可以看到有四条指令,对应下分别为:
- ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_UNUSED_HANDLER:对应$a = 1;
- ZEND_JMP_SPEC_HANDLER:跳转到下一条opcode
- ZEND_JMPNZ_SPEC_CV_HANDLER:进行while循环,如果循环条件不为0则跳回循环体
- ZEND_RETURN_SPEC_CONST_HANDLER:PHP虚拟机自动给脚本加的return
由此我们可以发现while语句的实现由ZEND_JMP_SPEC_HANDLER与ZEND_JMPNZ_SPEC_CV_HANDLER来实现,学过汇编的同学应该知道,JMP是无条件跳转的意思,在这里是跳转到下一个opcode,即JMPNZ,JMPNZ则是条件不为0时才会跳转。由此我们可以画出while的执行流程,如图所示:
至此我们可以得到while的执行流程了,当然如果想知道这些是如何进行运作的,建议大家去看一看pass_two这个函数,里边有如何设置opcode的。
结论
while语句并不是嵌套C语言的while语句,也不是我们之前的种种猜测,他的核心是通过jump,jumpnz来进行控制的。
ps:设计者可真是个天才。 :手动滑稽
延伸
如果说明白了while语句,那么do_while又是怎么一回事呢?大家可以自行思考一下
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。