Skip to content

Commit 1dddf7b

Browse files
committed
update
1 parent 517b366 commit 1dddf7b

File tree

1 file changed

+35
-3
lines changed

1 file changed

+35
-3
lines changed

3/function_implement.md

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,48 @@ function my_function(){
8888
另外参数还有其它的信息,比如默认值、引用传递,这些信息通过`zend_arg_info`结构记录:
8989
```c
9090
typedef struct _zend_arg_info {
91-
zend_string *name; //函数名
91+
zend_string *name; //参数名
9292
zend_string *class_name;
9393
zend_uchar type_hint; //显式声明的参数类型,比如(array $param_1)
9494
zend_uchar pass_by_reference; //是否引用传参,参数前加&的这个值就是1
95-
zend_bool allow_null; //是否允许为空
95+
zend_bool allow_null; //是否允许为NULL,注意:这个值并不是用来表示参数是否为必传的
9696
zend_bool is_variadic; //是否为可变参数,即...用法,与golang的用法相同,5.6以上新增的一个用法
9797
} zend_arg_info;
9898
```
99-
每个参数都有一个上面的结构,所有参数的结构保存在`zend_op_array.arg_info`数组中。
99+
每个参数都有一个上面的结构,所有参数的结构保存在`zend_op_array.arg_info`数组中,这里有一个地方需要注意:`zend_op_array->arg_info`数组保存的并不全是输入参数,如果函数声明了返回值类型则也会为它创建一个`zend_arg_info`,这个结构在arg_info数组的第一个位置,这种情况下`zend_op_array->arg_info`指向的实际是数组的第二个位置,返回值的结构通过`zend_op_array->arg_info[-1]`读取,编译时的处理具体如下。
100+
```c
101+
//函数参数的编译
102+
void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast)
103+
{
104+
zend_ast_list *list = zend_ast_get_list(ast);
105+
uint32_t i;
106+
zend_op_array *op_array = CG(active_op_array);
107+
zend_arg_info *arg_infos;
108+
109+
if (return_type_ast) {
110+
//声明了返回值类型:function my_func():array{...}
111+
//多分配一个zend_arg_info
112+
arg_infos = safe_emalloc(sizeof(zend_arg_info), list->children + 1, 0);
113+
...
114+
arg_infos->allow_null = 0;
115+
...
116+
//arg_infos指向了下一个位置
117+
arg_infos++;
118+
op_array->fn_flags |= ZEND_ACC_HAS_RETURN_TYPE;
119+
} else {
120+
//没有声明返回值类型
121+
if (list->children == 0) {
122+
return;
123+
}
124+
arg_infos = safe_emalloc(sizeof(zend_arg_info), list->children, 0);
125+
}
126+
...
100127

128+
op_array->num_args = list->children;
129+
//声明了返回值的情况下arg_infos已经指向了数组的第二个元素
130+
op_array->arg_info = arg_infos;
131+
}
132+
```
101133
#### 3.2.1.3 函数的编译
102134
我们在上一篇文章介绍过PHP代码的编译过程,主要是PHP->AST->Opcodes的转化,上面也说了函数其实就是将一组PHP代码编译为单独的opcodes,函数的调用就是不同opcodes间的切换,所以函数的编译过程与普通PHP代码基本一致,只是会有一些特殊操作,我们以3.2.1.2开始那个例子简单看下编译过程。
103135

0 commit comments

Comments
 (0)