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
546Zend引擎中定义了很多内部函数供用户在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