3.3.1 基本结构
最后更新于:2022-04-02 05:17:00
### 3.3.1 数据结构
执行流程中有几个重要的数据结构,先看下这几个结构。
#### 3.3.1.1 opcode
opcode是将PHP代码编译产生的Zend虚拟机可识别的指令,php7共有173个opcode,定义在`zend_vm_opcodes.h`中,PHP中的所有语法实现都是由这些opcode组成的。
```c
struct _zend_op {
const void *handler; //对应执行的C语言function,即每条opcode都有一个C function处理
znode_op op1; //操作数1
znode_op op2; //操作数2
znode_op result; //返回值
uint32_t extended_value;
uint32_t lineno;
zend_uchar opcode; //opcode指令
zend_uchar op1_type; //操作数1类型
zend_uchar op2_type; //操作数2类型
zend_uchar result_type; //返回值类型
};
```
#### 3.3.1.2 zend_op_array
`zend_op_array`是Zend引擎执行阶段的输入,整个执行阶段的操作都是围绕着这个结构,关于其具体结构前面我们已经讲过了。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/985c86ac9e827c2a05ed38d12c369fd0_436x245.png)
这里再重复说下zend_op_array几个核心组成部分:
* __opcode指令__:即PHP代码具体对应的处理动作,与二进制程序中的代码段对应
* __字面量存储__:PHP代码中定义的一些变量初始值、调用的函数名称、类名称、常量名称等等称之为字面量,这些值用于执行时初始化变量、函数调用等等
* __变量分配情况__:与字面量类似,这里指的是当前opcodes定义了多少变量、临时变量,每个变量都有一个对应的编号,执行初始化按照总的数目一次性分配zval,使用时也完全按照编号索引,而不是根据变量名索引
#### 3.3.1.3 zend_executor_globals
`zend_executor_globals executor_globals`是PHP整个生命周期中最主要的一个结构,是一个全局变量,在main执行前分配(非ZTS下),直到PHP退出,它记录着当前请求全部的信息,经常见到的一个宏`EG`操作的就是这个结构。
```c
//zend_compile.c
#ifndef ZTS
ZEND_API zend_compiler_globals compiler_globals;
ZEND_API zend_executor_globals executor_globals;
#endif
//zend_globals_macros.h
# define EG(v) (executor_globals.v)
```
`zend_executor_globals`结构非常大,定义在`zend_globals.h`中,比较重要的几个字段含义如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/dc6fee4115fea836048e332361ba7d7b_960x777.png)
#### 3.3.1.4 zend_execute_data
`zend_execute_data`是执行过程中最核心的一个结构,每次函数的调用、include/require、eval等都会生成一个新的结构,它表示当前的作用域、代码的执行位置以及局部变量的分配等等,等同于机器码执行过程中stack的角色,后面分析具体执行流程的时候会详细分析其作用。
```c
#define EX(element) ((execute_data)->element)
//zend_compile.h
struct _zend_execute_data {
const zend_op *opline; //指向当前执行的opcode,初始时指向zend_op_array起始位置
zend_execute_data *call; /* current call */
zval *return_value; //返回值指针
zend_function *func; //当前执行的函数(非函数调用时为空)
zval This; //这个值并不仅仅是面向对象的this,还有另外两个值也通过这个记录:call_info + num_args,分别存在zval.u1.reserved、zval.u2.num_args
zend_class_entry *called_scope; //当前call的类
zend_execute_data *prev_execute_data; //函数调用时指向调用位置作用空间
zend_array *symbol_table; //全局变量符号表
#if ZEND_EX_USE_RUN_TIME_CACHE
void **run_time_cache; /* cache op_array->run_time_cache */
#endif
#if ZEND_EX_USE_LITERALS
zval *literals; //字面量数组,与func.op_array->literals相同
#endif
};
```
zend_execute_data与zend_op_array的关联关系:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/005c7ed47923adba803d0f313417ad5f_450x676.png)
';