Skip to content

Commit 96a9c4a

Browse files
committed
change function
1 parent 679e064 commit 96a9c4a

File tree

2 files changed

+55
-53
lines changed

2 files changed

+55
-53
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* [1.2 PHP框架执行流程](base_process.md)
88
* 第2章 变量
99
* [2.1 变量的内部实现](zval.md)
10-
* [2.2 数组](zend_ht.md)
10+
* 2.2 数组(zend_ht.md)
1111
* 2.3 常量(var_common.md)
1212
* 第3章 Zend虚拟机
1313
* [3.1 PHP代码的编译](zend_compile.md)

function_implement.md

Lines changed: 54 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,11 @@
1-
# 函数实现
1+
## 3.2 函数实现
22

3-
## 1 用户自定义函数的实现
4-
5-
函数,通俗的讲就是将一堆操作打包成一个黑盒,给予特定的输入将对应特定的输出。
6-
7-
汇编中函数对应的是一组独立的汇编指令,然后通过call指令实现函数的调用,前面已经说过PHP编译的结果是opcode数组,与汇编指令对应,PHP用户自定义函数的实现就是将函数编译为独立的opcode数组,调用时分配独立的执行栈依次执行opcode。
8-
9-
10-
下面具体看下PHP中函数的结构:
11-
12-
```c
13-
typedef union _zend_function zend_function;
14-
15-
//zend_compile.h
16-
union _zend_function {
17-
zend_uchar type; /* MUST be the first element of this struct! */
18-
19-
struct {
20-
zend_uchar type; /* never used */
21-
zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */
22-
uint32_t fn_flags;
23-
zend_string *function_name;
24-
zend_class_entry *scope;
25-
union _zend_function *prototype;
26-
uint32_t num_args;
27-
uint32_t required_num_args;
28-
zend_arg_info *arg_info;
29-
} common;
30-
31-
zend_op_array op_array;
32-
zend_internal_function internal_function;
33-
};
34-
```
35-
这是一个union,因为PHP中函数分为两类:内部函数、用户自定义函数,内部函数是通过扩展或者内核提供的C函数,用户自定义函数就是我们在PHP中经常用到的function。
36-
37-
内部函数主要用到`internal_function`,而用户自定义函数编译完就是一个普通的opcode数组,用的是`op_array`(注意:op_array、internal_function是嵌入的两个结构,而不是一个单独的指针),除了这两个上面还有一个`type``common`,这俩是做什么用的呢?
38-
39-
经过比较发现`zend_op_array``zend_internal_function`结构的起始位置都有`common`中的几个成员,如果你对C的内存比较了解应该会马上想到它们的用法,实际`common`可以看作是`op_array``internal_function`的header,不管是什么哪种函数都可以通过`zend_function.common.xx`快速访问到`zend_function.zend_op_array.xx``zend_function.zend_internal_function.xx`,下面几个,`type`同理,可以直接通过`zend_function.type`取到`zend_function.op_array.type``zend_function.internal_function.type`
40-
41-
![php function](img/php_function.jpg)
42-
43-
函数是在编译阶段确定的,那么它们存在哪呢?
44-
45-
在PHP脚本的生命周期中有一个非常重要的值`executor_globals`(非ZTS下),类型是`struct _zend_executor_globals`,它记录着PHP生命周期中所有的数据,如果你写过PHP扩展一定用到过`EG`这个宏,这个宏实际就是对`executor_globals`的操作:`define EG(v) (executor_globals.v)`
46-
47-
`EG(function_table)`是一个哈希表,记录的就是PHP中所有的函数。
48-
49-
PHP在编译阶段将用户自定义的函数编译为独立的opcodes,保存在`EG(function_table)`中,调用时重新分配新的zend_execute_data(相当于运行栈),然后执行函数的opcodes,调用完再还原到旧的`zend_execute_data`,继续执行,关于zend引擎execute阶段后面会详细分析。
50-
51-
## 2 内部函数
3+
### 3.2.1 内部函数
524
内部函数指的是由内核、扩展提供的C语言编写的function,这类函数不需要经历opcode的编译过程,所以效率上要高于PHP用户自定义的函数。
535

546
Zend引擎中定义了很多内部函数供用户在PHP中使用,比如:define、defined、strlen、method_exists、class_exists、function_exists......等等,除了Zend引擎中定义的内部函数,PHP扩展中也提供了大量内部函数。
557

56-
### 2.1 内部函数结构
8+
#### 3.2.1.1 内部函数结构
579
上一节介绍`zend_function`为union,其中`internal_function`就是内部函数用到的,具体结构:
5810
```
5911
//zend_complie.h
@@ -79,7 +31,7 @@ typedef struct _zend_internal_function {
7931

8032
下面看下如何定义一个内部函数。
8133

82-
### 2.2 定义与注册
34+
#### 3.2.1.2 定义与注册
8335
内部函数与用户自定义函数冲突,用户无法在PHP代码中覆盖内部函数,执行PHP脚本时会提示error错误。
8436

8537
内部函数的定义非常简单,我们只需要创建一个普通的C函数,然后创建一个`zend_internal_function`结构添加到__EG(function_table)__(也可能是CG(function_table),取决于在哪一阶段注册)中即可使用,内部函数__通常__情况下是在php_module_startup阶段注册的,这里之所以说通常是按照标准的扩展定义,除了扩展提供的方式我们可以在任何阶段自由定义内部函数,当然并不建议这样做。下面我们先不讨论扩展标准的定义方式,我们先自己尝试下如何注册一个内部函数。
@@ -152,3 +104,53 @@ zend_module_entry xxxx_module_entry = {
152104
};
153105
```
154106
关于更多扩展中函数相关的用法会在后面扩展开发一章中详细介绍,这里不再展开。
107+
108+
### 3.2.2 用户自定义函数的实现
109+
110+
函数,通俗的讲就是将一堆操作打包成一个黑盒,给予特定的输入将对应特定的输出。
111+
112+
汇编中函数对应的是一组独立的汇编指令,然后通过call指令实现函数的调用,前面已经说过PHP编译的结果是opcode数组,与汇编指令对应,PHP用户自定义函数的实现就是将函数编译为独立的opcode数组,调用时分配独立的执行栈依次执行opcode。
113+
114+
115+
下面具体看下PHP中函数的结构:
116+
117+
```c
118+
typedef union _zend_function zend_function;
119+
120+
//zend_compile.h
121+
union _zend_function {
122+
zend_uchar type; /* MUST be the first element of this struct! */
123+
124+
struct {
125+
zend_uchar type; /* never used */
126+
zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */
127+
uint32_t fn_flags;
128+
zend_string *function_name;
129+
zend_class_entry *scope;
130+
union _zend_function *prototype;
131+
uint32_t num_args;
132+
uint32_t required_num_args;
133+
zend_arg_info *arg_info;
134+
} common;
135+
136+
zend_op_array op_array;
137+
zend_internal_function internal_function;
138+
};
139+
```
140+
这是一个union,因为PHP中函数分为两类:内部函数、用户自定义函数,内部函数是通过扩展或者内核提供的C函数,用户自定义函数就是我们在PHP中经常用到的function。
141+
142+
内部函数主要用到`internal_function`,而用户自定义函数编译完就是一个普通的opcode数组,用的是`op_array`(注意:op_array、internal_function是嵌入的两个结构,而不是一个单独的指针),除了这两个上面还有一个`type``common`,这俩是做什么用的呢?
143+
144+
经过比较发现`zend_op_array``zend_internal_function`结构的起始位置都有`common`中的几个成员,如果你对C的内存比较了解应该会马上想到它们的用法,实际`common`可以看作是`op_array``internal_function`的header,不管是什么哪种函数都可以通过`zend_function.common.xx`快速访问到`zend_function.zend_op_array.xx``zend_function.zend_internal_function.xx`,下面几个,`type`同理,可以直接通过`zend_function.type`取到`zend_function.op_array.type``zend_function.internal_function.type`
145+
146+
![php function](img/php_function.jpg)
147+
148+
函数是在编译阶段确定的,那么它们存在哪呢?
149+
150+
在PHP脚本的生命周期中有一个非常重要的值`executor_globals`(非ZTS下),类型是`struct _zend_executor_globals`,它记录着PHP生命周期中所有的数据,如果你写过PHP扩展一定用到过`EG`这个宏,这个宏实际就是对`executor_globals`的操作:`define EG(v) (executor_globals.v)`
151+
152+
`EG(function_table)`是一个哈希表,记录的就是PHP中所有的函数。
153+
154+
PHP在编译阶段将用户自定义的函数编译为独立的opcodes,保存在`EG(function_table)`中,调用时重新分配新的zend_execute_data(相当于运行栈),然后执行函数的opcodes,调用完再还原到旧的`zend_execute_data`,继续执行,关于zend引擎execute阶段后面会详细分析。
155+
156+

0 commit comments

Comments
 (0)