Skip to content

Commit 4ab8232

Browse files
committed
update
1 parent 1de9b7a commit 4ab8232

File tree

1 file changed

+96
-5
lines changed

1 file changed

+96
-5
lines changed

7/func.md

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,12 @@ typedef struct _zend_internal_function {
2525
```
2626
Common 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
7073
zend_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
430433
PHP_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

Comments
 (0)