最简单的获取函数调用者传递过来的参数便是使用zend_parse_parameters()函数。
定义参数默认值
借助zend_parse_parameters中的(|)参数,这个参数之前的参数被认为是必须的,之后的便认为是非必须的了,如果没有传递,则不会去修改载体。
可变参数(摘录)
有两种其它的zend_get_parameter_**函数,专门用来解决参数很多或者无法提前知道参数数目的问题。想一下php语言中var_dump()函数的用法,我们可以向其传递任意数量的参数,它在内核中的实现其实是这样的:
zend_parse_parameters()函数的前几个参数我们直接用内核里宏来生成便可以了,形式为:ZEND_NUM_ARGS() TSRMLS_CC,注意两者之间有个空格,但是没有逗号。从名字可以看出,ZEND_NUM_ARGS()代表这参数的个数。
紧接着需要传递个zend_parse_parameters()函数的参数是一个用于格式化的字符串,就像printf的第一个参数一样。下面表示了最常用的几个符号。
类型指定符 | 对应的C类型 | 描述 |
l | long | 符号整数 |
d | double | 浮点数 |
s | char *, int | 二进制字符串,长度 |
b | zend_bool | 逻辑型(1或0) |
r | zval * | 资源(文件指针,数据库连接等) |
a | zval * | 联合数组 |
o | zval * | 任何类型的对象 |
O | zval * | 指定类型的对象。需要提供目标对象的类类型 |
z | zval * | 无任何操作的zval |
除了上面定义的参数,还有其它的三个参数来增强我们接受参数的能力,如下:
<span class="sh_symbol">|</span> 它之前的参数都是必须的,之后的都是非必须的,也就是有默认值的。 <span class="sh_symbol">!</span> 如果接收了一个PHP语言里的null变量,则直接把其转成C语言里的NULL,而不是封装成IS_NULL类型的zval。 <span class="sh_symbol">/</span> 如果传递过来的变量与别的变量共用一个zval,而且不是引用,则进行强制分离,新的zval的is_ref__gc<span class="sh_symbol">==</span><span class="sh_number">0</span><span class="sh_symbol">,</span> <span class="sh_usertype">and</span><span class="sh_normal"> </span>refcount__gc<span class="sh_symbol">==</span><span class="sh_number">1</span><span class="sh_symbol">.</span>
下面列出几个传参例子
传字符参数
- PHP_FUNCTION(str){
- char *arg = NULL,*str = NULL;
- int arg_len, str_len = NULL;
- /**
- * s代表传递字符参数,下面函数里面的"ss"代表传的是字符型参数,两个ss代表定义了两个参数
- * &arg,&str取得参数地址,&arg_len,&str_len对应参数长度
- *如果传递给函数的参数数量小于zend_parse_parameters()要接收的参数数量,它便会执行失败,并返回FAILURE。
- */
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &arg, &arg_len, &str, &str_len) == FAILURE) {
- return;
- }
- PHPWRITE(arg, arg_len);
- php_printf(" ");
- PHPWRITE(str, str_len);
- }
传数组参数
- PHP_FUNCTION(array){
- zval *arr, **data;
- HashTable *arr_hash;
- HashPosition pointer;
- int array_count;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &arr) == FAILURE) {
- RETURN_NULL();
- }
- arr_hash = Z_ARRVAL_P(arr);
- array_count = zend_hash_num_elements(arr_hash);
- php_printf("The array passed contains %d elements ", array_count);
- for(zend_hash_internal_pointer_reset_ex(arr_hash, &pointer);
- zend_hash_get_current_data_ex(arr_hash, (void**) &data, &pointer) == SUCCESS;
- zend_hash_move_forward_ex(arr_hash, &pointer)) {
- convert_to_string_ex(data);
- PHPWRITE(Z_STRVAL_PP(data), Z_STRLEN_PP(data));
- php_printf(" ");
- }
- RETURN_TRUE;
- }
定义参数默认值
借助zend_parse_parameters中的(|)参数,这个参数之前的参数被认为是必须的,之后的便认为是非必须的了,如果没有传递,则不会去修改载体。
- ZEND_FUNCTION(str_1)
- {
- char *greeting = "Mr./Mrs."; //定义参数默认值,如果没有传递参数,则默认输出Mr./Mrs.
- int greeting_len = sizeof("Mr./Mrs.") - 1;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &greeting, &greeting_len) == FAILURE) {
- RETURN_NULL();
- }
- RETVAL_STRING(greeting, 1);
- }
可变参数(摘录)
有两种其它的zend_get_parameter_**函数,专门用来解决参数很多或者无法提前知道参数数目的问题。想一下php语言中var_dump()函数的用法,我们可以向其传递任意数量的参数,它在内核中的实现其实是这样的:
- PHP_FUNCTION(diy_var_dump)
- {
- int i, argc = ZEND_NUM_ARGS();
- zval ***args;
- args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0);
- if (ZEND_NUM_ARGS() == 0 || zend_get_parameters_array_ex(argc, args) == FAILURE)
- {
- efree(args);
- WRONG_PARAM_COUNT;
- /*
- *这里,WRONG_PARAM_COUNT是一个宏定义(zend_API.h):
- *ZEND_API void wrong_param_count(void);
- *#define WRONG_PARAM_COUNT { wrong_param_count(); return; }
- *如果参数个数错误,WRONG_PARAM_COUNT会打印出相应的错误信息。
- */
- }
- for (i=0; i<argc; i++)
- {
- php_var_dump(args[i], 1 TSRMLS_CC);
- }
- efree(args); //稀放内存
- }