@@ -25,9 +25,12 @@ typedef struct _zend_internal_function {
2525``` 
2626Common elements就是与用户函数相同的头部,用来记录函数的基本信息:函数类型、参数信息、函数名等,handler是此内部函数的具体实现,PHP提供了一个宏用于此handler的定义:` PHP_FUNCTION(function_name) ` 或` ZEND_FUNCTION() ` ,展开后:
2727``` c 
28- void  (*handler)(zend_execute_data *execute_data, zval *return_value)
28+ void  *zif_function_name (zend_execute_data * execute_data, zval * return_value)
29+ {
30+  ...
31+ }
2932``` 
30- 也就是内部函数会得到两个参数 :execute_data、return_value,execute_data不用再说了,return_value是函数的返回值,这两个值在扩展中会经常用到。
33+ PHP为函数名加了"zif_"前缀,gdb调试时记得加上这个前缀;另外内部函数定义了两个参数 :execute_data、return_value,execute_data不用再说了,return_value是函数的返回值,这两个值在扩展中会经常用到。
3134
3235比如要在扩展中定义两个函数:my_func_1()、my_func_2(),首先是编写函数: 
3336```c 
@@ -65,12 +68,12 @@ const zend_function_entry mytest_functions[] = {
6568#define  ZEND_FENTRY (zend_name, name, arg_info, flags ) { #zend_name, name, arg_info, (uint32_t) (sizeof(arg_info)/sizeof(struct _ zend_internal_arg_info)-1), flags },
6669#define ZEND_FN(name) zif_ ##name
6770``` 
68- 内部函数的名称前加了`zif_`前缀,以防与内核中的函数冲突,所以如果想用gdb调试扩展定义的函数记得加上这个前缀。 最后将`zend_module_entry. functions`设置为`timeout_functions`即可:
71+ 最后将`zend_module_entry-> functions`设置为`timeout_functions`即可: 
6972```c 
7073zend_module_entry mytest_module_entry = { 
7174 STANDARD_MODULE_HEADER, 
7275 "mytest", 
73-  mytest_functions, 
76+  mytest_functions, //functions  
7477 NULL, //PHP_MINIT(mytest), 
7578 NULL, //PHP_MSHUTDOWN(mytest), 
7679 NULL, //PHP_RINIT(mytest), 
@@ -426,7 +429,7 @@ const zend_function_entry mytest_functions[] = {
426429};
427430``` 
428431引用参数通过` zend_parse_parameters() ` 解析时只能使用"z"解析,不能再直接解析为zend_value了,否则引用将失效:
429- ``` 
432+ ``` c 
430433PHP_FUNCTION (my_func_1)
431434{
432435 zval * lval; //必须为zval,定义为zend_long也能解析出,但不是引用
@@ -453,7 +456,95 @@ echo $a;
453456>  __ Note:__  参数数组与zend_parse_parameters()有很多功能重合,两者都会生效,对zend_internal_arg_info验证在zend_parse_parameters()之前,为避免混乱两者应该保持一致;另外,虽然内部函数的参数数组并不强制定义声明,但还是建议声明。
454457
455458### 7.6.4 函数返回值  
459+ 调用内部函数时其返回值指针作为参数传入,这个参数为` zval *return_value ` ,如果函数有返回值直接设置此指针即可,需要特别注意的是设置返回值时需要增加其引用计数,举个例子来看:
460+  ```c
461+ PHP_FUNCTION(my_func_1)
462+ {
463+  zval * arr;
464+ 
465+  if(zend_parse_parameters(ZEND_NUM_ARGS(), "a", &arr) == FAILURE){ 
466+   RETURN_FALSE; 
467+  } 
456468
469+  //增加引用计数 
470+  Z_ADDREF_P(arr); 
471+ 
472+  //设置返回值为数组: 
473+  //return_value->u1.type = IS_ARRAY;  
474+  //return_value->value->arr = arr->value->arr; 
475+  ZVAL_ARR(return_value, Z_ARR_P(arr)); 
476+ } 
477+ ``` 
478+ 此函数接收一个数组,然后直接返回该数组,相当于: 
479+ ```php 
480+ function my_func_1($arr){ 
481+  return $arr; 
482+ } 
483+ ``` 
484+ 调用该函数:
485+ ``` php 
486+ $a = array(); //$a -> zend_array(refcount:1)
487+ $b = my_func_1($a); //传参后:参数arr -> zend_array(refcount:2)
488+  //然后函数内部赋给了返回值:$b,$a,arr -> zend_array(refcount:3)
489+  //函数return阶段释放了参数:$b,$a -> zend_array(refcount:2)
490+ var_dump($b);
491+ =============[output]===========
492+ array(0) {
493+ }
494+ ``` 
495+ 虽然可以直接设置return_value,但实际使用时并不建议这么做,因为PHP提供了很多专门用于设置返回值的宏,这些宏定义在` zend_API.h ` 中:
496+ ``` c 
497+ // 返回布尔型,b:IS_FALSE、IS_TRUE
498+ #define  RETURN_BOOL (b )  { RETVAL_BOOL(b); return; } 
499+ 
500+ // 返回NULL
501+ #define  RETURN_NULL () { RETVAL_NULL(); return;}
502+ 
503+ // 返回整形,l类型:zend_long
504+ #define  RETURN_LONG (l )  { RETVAL_LONG(l); return; } 
505+ 
506+ // 返回浮点值,d类型:double
507+ #define  RETURN_DOUBLE (d )  { RETVAL_DOUBLE(d); return; } 
508+ 
509+ // 返回字符串,可返回内部字符串,s类型为:zend_string *
510+ #define  RETURN_STR (s )  { RETVAL_STR(s); return; } 
511+ 
512+ // 返回内部字符串,这种变量将不会被回收,s类型为:zend_string *
513+ #define  RETURN_INTERNED_STR (s )  { RETVAL_INTERNED_STR(s); return; } 
514+ 
515+ // 返回普通字符串,非内部字符串,s类型为:zend_string *
516+ #define  RETURN_NEW_STR (s )  { RETVAL_NEW_STR(s); return; } 
517+ 
518+ // 拷贝字符串用于返回,这个会自己加引用计数,s类型为:zend_string *
519+ #define  RETURN_STR_COPY (s )  { RETVAL_STR_COPY(s); return; } 
520+ 
521+ // 返回char *类型的字符串,s类型为char *
522+ #define  RETURN_STRING (s )  { RETVAL_STRING(s); return; } 
523+ 
524+ // 返回char *类型的字符串,s类型为char *,l为字符串长度,类型为size_t
525+ #define  RETURN_STRINGL (s, l )  { RETVAL_STRINGL(s, l); return; } 
526+ 
527+ // 返回空字符串
528+ #define  RETURN_EMPTY_STRING () { RETVAL_EMPTY_STRING(); return; }
529+ 
530+ // 返回资源,r类型:zend_resource *
531+ #define  RETURN_RES (r )  { RETVAL_RES(r); return; } 
532+ 
533+ // 返回数组,r类型:zend_array *
534+ #define  RETURN_ARR (r )  { RETVAL_ARR(r); return; } 
535+ 
536+ // 返回对象,r类型:zend_object *
537+ #define  RETURN_OBJ (r )  { RETVAL_OBJ(r); return; } 
538+ 
539+ // 返回zval
540+ #define  RETURN_ZVAL (zv, copy, dtor )  { RETVAL_ZVAL(zv, copy, dtor); return; } 
541+ 
542+ // 返回false
543+ #define  RETURN_FALSE   { RETVAL_FALSE; return; } 
544+ 
545+ // 返回true
546+ #define  RETURN_TRUE   { RETVAL_TRUE; return; } 
547+ ``` 
457548### 7.6.5 函数调用  
458549
459550
0 commit comments