【PHP7源码学习】2019-04-04 PHP中while的实现

grape

全部视频:https://segmentfault.com/a/11...


引入

在我们平常写PHP代码总是会用到while语句,那么我们有没有去考虑过while语句是怎么实现的呢?

我们来看下面的这段代码:

我们知道这段代码是个死循环,毋庸置疑,但是在PHP中,它是如何做到的呢?请看下文。

分析

首先,我们自己分析一下这个while语句,如果让我们来设计,我们会如何设计呢?笔者写出脑补几点:

  1. PHP是C语言编写的,直接去沿用C的语法,while套用。
  2. 在源码设计中加入goto语句。
  3. for循环嵌套if语句
  4. 等等(大家可以头脑风暴下)

接下来我们看一下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又是怎么一回事呢?大家可以自行思考一下

你可能感兴趣的:(php)