上文我们学会了如何快速的进行一个PHP扩展的hello world! 下面我们将学习如何传递参数
###必要知识点
1.变量存储结构(php 5.6 src/ZEND/zend.h)
1typedef union _zvalue_value { 2 long lval; // long value 3 double dval; // double value 4 struct { 5 char *val; 6 int len; 7 } str; 8 HashTable *ht; // 9 zend_object_value obj; 10 zend_ast *ast; 11} zvalue_value; 12 13struct _zval_struct { 14 // Variable information 15 zvalue_value value; // value 16 zend_uint refcount\__gc; 17 zend_uchar type; // active type 18 zend_uchar is_ref\__gc; 19};
最终形成一个[这个就是PHP的变量] typedef struct _zval_struct zval; 其实际值存储在 zval.value 判断是否为引用 is_ref__gc 判断引用的次数 refcount gc [PHP的写时复制特性] 判断值的类型 type
###源码分析 我们打开zend_API.c 可以看到很多关于变量的处理的函数。
比如 ZEND_API int zend_get_parameters(int ht, int param_count, ...)
ZEND_API int _zend_get_parameters_array(int ht, int param_count, zval **argument_array TSRMLS_DC)
ZEND_API int zend_get_parameters_ex(int param_count, ...)
ZEND_API int _zend_get_parameters_array_ex(int param_count, zval ***argument_array TSRMLS_DC)
ZEND_API int zend_parse_parameters ......
我们来参考一下原来的代码。 打开文件 phpsrc/ext/standard/var.c
我们看PHP是如何实现var_dump方法的
1 87 PHPAPI void php_var_dump(zval **struc, int level TSRMLS_DC) /* {{{ */ 2 88 { 3 89 HashTable *myht; 4 90 const char *class_name; 5 91 zend_uint class_name_len; 6 92 int (*php_element_dump_func)(zval** TSRMLS_DC, int, va_list, zend_hash_key*); 7 93 int is_temp; 8 94 9 95 if (level > 1) { 10 96 php_printf("%*c", level - 1, ' '); 11 97 } 12 98 13 99 switch (Z_TYPE_PP(struc)) { 14 100 case IS_BOOL: 15 101 php_printf("%sbool(%s)\n", COMMON, Z_LVAL_PP(struc) ? "true" : "false"); 16 102 break; 17 18 ...... 19 } 20 21 22173 line 23PHP_FUNCTION(var_dump) 24 173 { 25 174 zval ***args; 26 175 int argc; 27 176 int i; 28 177 29 178 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc) == FAILURE) { 30 179 return; 31 180 } 32 181 33 182 for (i = 0; i < argc; i++) { 34 183 php_var_dump(args[i], 1 TSRMLS_CC); 35 184 } 36 185 efree(args); 37 186 } 38
可以发现 和上节说的一样 首先定义 PHP_FUNCTION(函数名){实现} 那我们发现没有参数怎么办?
这里就要用到我们开始说的方法了 178行 zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argc)
明显由其获得了 参数 和 参数的个数
然后调用了函数的实现体
到此,PHP扩展开发怎么调用函数,思路就已经很明确了。
###实践 我们还是依照昨天的example,今天我们写一个A+B的方法
首先,我们定义一个方法
1 PHP_FUNCTION(example_add){ 2 long a,b; 3 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &a, &b) == FAILURE) { 4 return; 5 } 6 7 //添加要做的操作 8 9 }
我们加入我们要实现的A+B功能
printf("%d\n",a+b);
同样,我们添加到functions
1static const zend_function_entry t2_functions[] = { 2 //在这加入方法的定义 3 PHP_FE(example_add,NULL) 4 {NULL, NULL, NULL} 5}
重新编译安装,我们就可以运行
<?php example_add(3,5); ?>
输出8