【PHP7源码分析】PHP7语言的执行原理
发布时间:2022-09-27 11:48:41 所属栏目:PHP教程 来源:
导读: 我们常用的高级语言有很多种,比较出名的有CC++、Python、 PHP、Go、Pascal等。而这些语言根据运行的方式不同,大体分为两种:编译型语言和解释型语言。
其中,编译型语言包括CC++、Pascal、Go等。这里说
其中,编译型语言包括CC++、Pascal、Go等。这里说
我们常用的高级语言有很多种,比较出名的有CC++、Python、 PHP、Go、Pascal等。而这些语言根据运行的方式不同,大体分为两种:编译型语言和解释型语言。 其中,编译型语言包括CC++、Pascal、Go等。这里说的编译是指在应用源程序执行之前php语言基础教程,就将程序源代码“翻译”成汇编语言,然后进一步根据软硬件环境编译成目标文件。一般我们称完成编译工作的工具叫编译器。而解释型语言,在程序运行时才被“翻译”为机器语言。但是执行一次“翻译”一次,所以执行效率较低。解释器的工作就是解释性语言中,负责“翻译”源代码的程序。 下面我们更详细地讨论一下编译型语言和解释性语言的运行方式。 一、编译型语言与解释型语言 我们知道,对于一段C语言代码,需要经过预编译、编译、汇编和链接,才能成为可执行的二进制文件。以hello.c为例: #include int main(){ printf("hello world"); return 1; } 对于这段C代码,main是程序入口函数,实现的功能是打印字符串“hello world” 到屏幕上。编译和执行过程如图1所示。 第1步:C语言代码预处理(比如依赖处理、宏替换等)。如以上代码示例,#inlcude就会在预处理阶段被替换。 第2步:编译。编译器会把C语言翻译成汇编语言程序,一条C语言通常便以为多条汇编代码。同时编译器会对程序进行优化,生成目标汇编程序。 第3步:编译得到的汇编语言通过汇编器再汇编成目标程序hello.o。 第4步:链接。程序中往往包含一些共享目标文件,如示例程序中的printf()函数,位于静态库,需要经过链接器(如Uinx连接器ld)进行链接。 以C语言为代表的编译型语言,代码发生更新都要经过以上步骤: 我们区别编译型语言与解释型语言,主要立足于源代码被编译成目标平台CPU指令的时机。对于编译型语言,编译结果已经是针对当前CPU体系的指令;而解释型语言,需要先编译成中间代码,再经由该解释型语言的特定虚拟机,翻译成特定CPU体系的指令被执行。解释型语言是在运行过程中,翻译为目标平台的指令。常说解释型语言“慢”,主要也是慢在这里。 在PHP7中php语言基础教程,源代码首先将进行词法分析,将源代码切割为多个字符串单元,分割后的字符串称之为Token。而一个个独立的Token无法表达完整语义,需经过语法分析阶段,将Token转换为抽象语法树(简称AST)。之后,抽象语法树被转换为机器指令执行。在PHP中,这些指令称为opcode(后文会对opcode做更详细的解释,此处读者可以看待为CPU指令)。 到AST的生成这一步,编译型语言与解释型语言所需经历的过程相似。从抽象语法树之后开始产生差异。 第1步:源码通过词法分析得到Token; 第2步:基于语法分析器生成抽象语法树(AST); 第3步:抽象语法树转换为Opcodes(opcode指令集合),PHP解释执行Opcodes。 接下来我们在基本步骤的基础上,细化PHP语言的执行原理,试图更清晰地建立认知。 二、PHP7的执行原理概述 首先我们补充说明下前文提到的PHP7程序执行过程,请参见图3。 第1步:词法分析将PHP代码转换为有意义的标识Token。该步骤的词法分析器使用Re2c实现的。 第2步:语法分析将Token和符合文法规则的代码生成抽象语法树。语法分析器基于Bison实现。语法分析使用了巴科斯范式(BNF)来表达文法规则,Bison借助状态机、状态转移表和压栈、出栈等一系列操作,生成抽象语法树。 第3步:上步的抽象语法树生成对应的opcode,被虚拟机执行。opcode是PHP7定义的一组指令标识,指令对应着相应的handler(处理函数)。当虚拟机调用opcode,会找到opcode背后的处理函数,执行真正的处理。以我们常见的echo语句为例,其对应的opcode便是ZEND_ECHO。 下面,我们通过一段示例代码,来建立PHP7运转的初步理解。 示例代码如下: 从图3可知,这段代码首先会被切割为Token。 1. Token Token是PHP代码被切割成的有意义的标识。本书介绍的PHP7版本中有137 种Token,在zend_language_parser.h文件中做了定义: /* Tokens. */#define END 0#define T_INCLUDE 258#define T_INCLUDE_ONCE 259…#define T_ERROR 392 更多Token的含义,感兴趣的读者可以参考《PHP 7底层设计与源码实现》附录。 PHP提供了token_get_all()函数来获取PHP代码被切割后的Token,可以在深入源码学习前,粗略查看PHP代码被切割后的Token。如下代码片段: /home/vagrant/php7/bin/php –r 'print_r(Token_get_all(" 输出结果为: Array ( [0] => Array ( [0] => 379 [1] => 1 ) [1] => Array ( [0] => 328 [1] => echo [2] => 1 ) [2] => Array ( [0] => 382 [1] => [2] => 1 ) [3] => Array ( [0] => 323 [1] => "hello world" [2] => 1 ) [4] => ; ) 上文输出中,二维数组的每个成员数组第一个值为Token对应的枚举值;第二个值为Token对应的原始字符串内容;第三个值为代码对应的行号。可以看出,词法解析器将 (编辑:海洋资讯信息网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
站长推荐