PHP就像是一个乐高搭建出来的城堡,把城堡拆开,就是一个一个小零件,当我们把它重新按照不同的方式组装起来,就能创造另一个东西。
概述
PHP就是一个C程序,有main函数。我们写的PHP代码就是这个程序的输入,然后经过内核的处理输出结果,内核将PHP代码翻译为C程序可识别的数据并执行。
代码编译执行流程为:
PHP代码 >> parser 语法词法解析 >> AST 抽象语法树 >> Opcode 中间字节码 >> 执行
一些概念说明
词法分析概念
词法分析是编译器前段的第一个部分,它的任务是完成从字符流到记号流的转换。
字符流:就是源代码
记号流:自定义的数据结构,方便编译器后期处理
比如说,字符流就是一群人,记号流就是给每个人打上标签,方便后面归类分工。
也就是说,源代码本身就是字符串,要把他们放到定义好的数据结构中,这样的话每个字符串就有意义了,后面就可以对数据结构内的数据进一步处理。
语法分析概念
词法分析器把源代码的词标上了记号,但是对于int、x、=、1、;、还不知道如何检测语法错误,不知道如何分割上下文。
语法分析就是做这个事的,以词法分析器生成的单词符号序列作为输入,构造一棵AST抽象语法树。
AST抽象语法树
是源代码的抽象语法结构的树状表现形式。
举个例子,比如浏览器打开网页,浏览器就会先把源代码转换成AST来进行进一步的分析等其他操作。
Opcode
最小操作单元
语法分析 && 语法分析
首先PHP用re2c词法分析器、yacc语法分析器,对代码进行分析。
词法分析将源文件转换成token流,语法分析将token流转换成AST抽象语法树,同时验证语法,如果语法有错就抛出语法错误。
https://github.com/php/php-src/blob/PHP-7.4.9/Zend/zend_language_scanner.l 词法分析
https://github.com/php/php-src/blob/PHP-7.4.9/Zend/zend_language_parser.y 语法分析
1 | <ST_IN_SCRIPTING>"echo" { |
1 | %token T_ECHO "echo (T_ECHO)" |
比如 echo $a; 在碰到这句首先会匹配到echo,用 zend_language_scanner.l 词法分析后返回 T_ECHO 标记。
然后再用 zend_language_parser 语言分析,并挂到AST抽象语法树上。
(语法分析中,有一个枚举函数 yytokentype ,T_ECHO对应的值是324,根据值case到后,进行语法解析。这里指的只是echo,如果有其他词比如if、else、foreach、运算符号、等等也都会单独case到后被单独解析。)
1 | case 324: |
转opcode && 执行
解析AST,生成opcode。
字节码主要由zend_compile.c文件处理
https://github.com/php/php-src/blob/PHP-7.4.9/Zend/zend_compile.c
最后在Zend虚拟机中由zend_execute()执行生成的opcode。
https://raw.githubusercontent.com/php/php-src/PHP-7.4.9/Zend/zend_vm_execute.h
参考
https://blog.lou00.top/2019/11/25/PHP%E7%9A%84%E7%BC%96%E8%AF%91%E4%B8%8E%E6%89%A7%E8%A1%8C%E7%AC%94%E8%AE%B0%20-%20PHP%E7%9A%84%E7%BC%96%E8%AF%91/index.html
https://programtip.com/zh/art-130198
https://blog.csdn.net/qq_32783703/article/details/104062405
https://zhuanlan.zhihu.com/p/78454124
https://www.tuine.me/php7-internal
https://www.cnblogs.com/nzhl/p/5461037.html
https://blog.csdn.net/huangpb123/article/details/84799198
https://tech.youzan.com/understanding-opcode-optimization-in-php/