最简单的获取函数调用者传递过来的参数便是使用zend_parse_parameters()函数。
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
除了上面定义的参数,还有其它的三个参数来增强我们接受参数的能力,如下:
|它之前的参数都是必须的,之后的都是非必须的,也就是有默认值的。
!如果接收了一个PHP语言里的null变量,则直接把其转成C语言里的NULL,而不是封装成IS_NULL类型的zval。
/如果传递过来的变量与别的变量共用一个zval,而且不是引用,则进行强制分离,新的zval的is_ref__gc==0, and refcount__gc==1.
下面列出几个传参例子
传字符参数
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
{
php_var_dump(args[i], 1 TSRMLS_CC);
}
efree(args); //稀放内存
}