一、执行原理

(一)理论概念

  1. 首先进行词法分析,将源代码切割为多个字符串单元,分割后的字符串称为Token。
    该步骤的词法分析器使用Re2c实现。
  2. 由于Token无法表达完整语义,故需要基于语法分析器将Token和符合文法规则的代码生成抽象语法树(也就是上一届最后说的 AST)。
    语法分析器基于Bison(一种通用解析器生成器)实现,使用了链接: BNF(Backus-NaurForm 巴克斯范式).来表达文法规则,Bison借助状态机、状态转移表和压栈、出栈等一系列操作生成抽象语法树。
  3. 抽象语法树被转换为机器指令执行。这些指令称为opcode,这里可以理解为CPU指令。抽象语法树转换为opcode指令集合,PHP解释执行opcode。

这是来自知乎的一个简易流程说明。

[ PHP源码 ]
=> 词法分析 / 语法分析 -> [ 抽象语法树(AST) ]
=> 字节码编译器 -> [ Zend字节码(指令集为 Zend opcodes) ]
=> 字节码解释器 -> [ 程序运行结果 ]

(二) 代码说明

1. Token

# 在PHP中,提供了Token_get_all()这个函数来获取PHP代码被切割后的Token
php -r 'print_r(Token_get_all("<?php echo \"Hello World\";"));';
# 执行结果
Array
(
    [0] => Array
        (
            [0] => 379 //每个成员数组的第一个值为Token对应的枚举值
            [1] => <?php
            [2] => 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对应的枚举值。
字符串“<?php”切割后对应的Token值为379:源码【#define T_OPEN_TAG 379】
echo 对应的Token值为328:源码【#define T_ECHO 328】
空格 对应的Token值为382:源码【#define T_WHITESPACE】
字符串“Hello World” 对应的Token值为 323 源码 【#define T_CONSTANT_ENCAPSED_STRING】

2.AST(抽象语法树)

上面讲了Token,可以看出每个Token并不能表达出完整的语义,需要借助语法分析器依据规则进行组织串联,检查语法,匹配Token。

而php7组织串联的产物就是AST(Abstrat Syntax Tree),实现了PHP编译器和解释器解耦,提升了可维护性。

抽象语法树具有树状结构。

节点分为多种类型,对应着php的语法。

3.opcodes

AST扮演了源码到中间代码的临时存储介质的角色,还需将其转换为opcode才能被引擎直接执行。
opcode是单条指令,opcodes它的集合形式,是php执行过程的中间代码。

二、内核架构

在这里插入图片描述

(一)Zend引擎

词法语法分析、AST编译、opcodes的执行、PHP的变量设计、内存管理、进程管理等都在Zend引擎中实现。

(二)PHP层

Zend引擎为PHP提供方基础能力,PHP层主要处理来自外部的交互

(三)SAPI (Server API)

包含 cli SAPI和 fpm SAPI。

(四)扩展EXT

php主要包含源码目录:sapi、Zend、main、ext、TSRM

sapi

sapi目录是对输入和输出层的抽象,是PHP提供对外服务的规范。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐