execute php,PHP execute_data

这阵子想研究下PHP Generator的实现,发现对于Generator很重要的一个数据结构为_zend_execute_data,在PHP源码中通常是一个execute_data变量,与该变量相关的宏是#define EX(element) execute_data.element。

查看了下opcode的执行,发现_zend_execute_data对于PHP代码的执行也是关键的数据结构。所以本文主要围绕该数据结构展开来讲~

PHP代码的执行

总所周知,PHP代码的执行会经历:词法分析->语法分析->opcode生成->执行opcode。

对“opcode生成->执行opcode”展开来就是:

zend_compile_file()将PHP代码文件编译为op_array(opcode的数组)

初始化一个execute_data,之后赋值:EX(op_array) = op_array;EX(opline) = op_array->opcodes;

执行opcode:EX(opline)->handler(execute_data),这是在一个while语句中执行的。

execute_data可以理解为一个执行上下文,通过gdb单步调试,发现:

当我们执行php hello.php时,会创建一个execute_data,当出现include/require或函数调用时,则会新建一个execute_data后,切换到新的execute_data执行,当一个execute_data执行结束,会切换到上层的execute_data继续执行。

c1a3e1bb2571d29a8d38a3a6238fd4c1.png

每一个op_array的最后一条opcode都是RETURN,这也是为什么在类似PHP框架的配置文件中可以直接<?php return [配置信息]; ?>,而加载配置文件的代码为$config = require('配置文件');。

通过VLD扩展可以打印出一个PHP执行文件产生的opcode:

f9653e95a4196849e4d75a3f1d5aa094.png

如上图,就存在两个op_array,一个是FunCall.php文件的,一个是foo函数的。

_zend_execute_data结构体说明

未标注释的结构体成员尚未了解其作用

6b45c06764cddf9c379e2f7915669918.png

以一个例子说明下EX(object)、EX(current_scope)、EX(current_called_scope)、EX(current_this)、EX(call)、EG(This)、EG(scope)、EG(called_scope)在函数调用时的变化:

例子代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28<?php

class bar

{

static public function pp($param)

{

echo $param;

}

}

class foo

{

public function p($param)

{

self::spp($param);

bar::pp($param);

}

static private function spp($param)

{

echo $param;

}

}

function ff()

{

$foo = new foo();

$foo->p("haha\n");

}

ff();

调用图(图太大,请另起一个标签页查看= =):

be13e95494ed03a559a1ab6e1012d536.png

_zend_execute_data结构体的初始化

在Zend/zend_execute.c中的函数zend_execute_data *i_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC)负责创建新的execute_data,其内存分配是在EG(argument_stack)(指向某一段内存,_zend_vm_stack数据结构,不足时会增长)上进行的。

1

2

3

4

5

6typedef struct _zend_vm_stack *zend_vm_stack;

struct _zend_vm_stack {

void **top;

void **end;

zend_vm_stack prev;

};

在一个初始化好的EG(argument_stack)上分配一个execute_data:

2f1044bed65d3de553484a4f3c02c422.png

EG(argument_stack)上没有足够的内存分配一个execute_data时,新申请一个_zend_vm_stack:

00045f4706cef6e6c5d1f9a1f72aae46.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值