@@ -396,24 +396,61 @@ ZEND_END_ARG_INFO()
396396//声明为可变参数
397397#define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name) { #name, NULL, 0, pass_by_ref, 0, 1 },
398398```
399-
399+ 举个例子来看:
400+ ``` php
401+ function my_func_1(& $a, Exception $c){
402+ ...
403+ }
404+ ```
405+ 用内核实现则可以这么定义:
406+ ``` c
407+ ZEND_BEGIN_ARG_INFO_EX (arginfo_my_func_1, 0, 0, 1)
408+ ZEND_ARG_INFO(1, a) //引用
409+ ZEND_ARG_OBJ_INFO(0, b, Exception, 0) //注意:这里不要把字符串加""
410+ ZEND_END_ARG_INFO()
411+ ```
400412展开后:
401413```c
402414static const zend_internal_arg_info name[] = {
403415 { (const char*)(zend_uintptr_t)(2), NULL, 0, 0, 0, 0 },
404- { name , NULL, 0, 0, 0, 0 },
405- { id, NULL, 0 , 1, 0, 0 },
416+ { "a" , NULL, 0, 0, 0, 0 },
417+ { "b", "Exception", 8 , 1, 0, 0 },
406418}
407419```
408- 第一个数组元素用于记录必传参数的数量以及返回值是否为引用。定义完这个数组接下来就需要把这个数组告诉函数, ` PHP_FE() ` 宏的第二个参数就是接收这个数组的 :
420+ 第一个数组元素用于记录必传参数的数量以及返回值是否为引用。定义完这个数组接下来就需要把这个数组告诉函数:
409421``` c
410422const zend_function_entry mytest_functions[] = {
411423 PHP_FE (my_func_1, arginfo_my_func_1)
412424 PHP_FE(my_func_2, NULL)
413425 PHP_FE_END //末尾必须加这个
414426};
415427```
428+ 引用参数通过` zend_parse_parameters() ` 解析时只能使用"z"解析,不能再直接解析为zend_value了,否则引用将失效:
429+ ```
430+ PHP_FUNCTION(my_func_1)
431+ {
432+ zval *lval; //必须为zval,定义为zend_long也能解析出,但不是引用
433+ zval *obj;
416434
435+ if(zend_parse_parameters(ZEND_NUM_ARGS(), "zo", &lval, &obj) == FAILURE){
436+ RETURN_FALSE;
437+ }
438+
439+ //lval的类型为IS_REFERENCE
440+ zval *real_val = Z_REFVAL_P(lval); //获取实际引用的zval地址:&(lval.value->ref.val)
441+ Z_LVAL_P(real_val) = 100; //设置实际引用的类型
442+ }
443+ ```
444+ ``` php
445+ $a = 90;
446+ $b = new Exception;
447+ my_func_1($a, $b);
448+
449+ echo $a;
450+ ==========[output]===========
451+ 100
452+ ```
453+ > __ Note:__ 参数数组与zend_parse_parameters()有很多功能重合,两者都会生效,对zend_internal_arg_info验证在zend_parse_parameters()之前,为避免混乱两者应该保持一致;另外,虽然内部函数的参数数组并不强制定义声明,但还是建议声明。
417454
418455### 7.6.4 函数返回值
419456
0 commit comments