@@ -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