PHP扩展开发(6):接收参数

文章目录

函数的参数则是PHP代码层和C代码层之间交换数据的唯一途径,因为PHP的调用语法是动态的,不会做任何错误检查,所以检查参数工作需要交给开发PHP扩展人员完成,看一下我们在快速入门里面的一段代码,使用zend_parse_parameters来解析参数:

PHP_FUNCTION(say_goodbye)
{
    char *arg = NULL;
    int arg_len, len;
    char *strg;

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
        return;
    }

    len = spprintf(&strg, 0, "Goodbye %s\n", arg);
    RETURN_STRINGL(strg, len, 0);
}

获取参数数量

PHP无法根据函数的显式声明来对调用进行语法检查,而且它还支持可变参数,所以我们就不得不在所调用函数的内部来获取参数个数。我们可以使用宏ZEND_NUM_ARGS来获取参数个数,如下面的代码:

if(ZEND_NUM_ARGS() != 2)
{
    WRONG_PARAM_COUNT
}

这段代码使用宏WRONG_PARAM_COUNT抛出一个参数个数错误。

解析参数

开发PHP扩展时,解析参数基本是使用标准方式zend_parse_parameters,使用方式如下所示:

int zend_parse_parameters(int num_args TSRMLS_DC, char *type_spec, ...);

num_args参数指定参数个数,前面介绍过使用ZEND_NUM_ARGS获取参数个数;TSRMLS_DC宏指定线程安 全;type_spec参数是一个字符串,指定各个参数的类型,每个参数类型用一个字母表示。如果成功地解析和接收到了参数并且在转换期间也没出现错误, 那么这个函数就会返回SUCCESS,否则返回FAILURE,各个参数类型的字母标识如下:

l – 长整数 
d – 双精度浮点数 
s – 字符串 (也可能是空字节)和其长度 
b – 布尔值 
r – 资源, 保存在 zval* 
a – 数组, 保存在 zval* 
o – (任何类的)对象, 保存在 zval* 
O – (由class entry 指定的类的)对象, 保存在 zval* 
z – 实际的 zval*

在设置参数类型时,还可以使用以下几个特殊的字符:

| – 表明剩下的参数都是可选参数。如果用户没有传进来这些参数值,那么这些值就会被初始化成默认值。 
/ – 表明参数解析函数将会对剩下的参数以 SEPARATE_ZVAL_IF_NOT_REF() 的方式来提供这个参数的一份拷贝,除非这些参数是一个引用。 
! – 表明剩下的参数允许被设定为 NULL(仅用在 a、o、O、r和z身上)。如果用户传进来了一个 NULL 值,则存储该参数的变量将会设置为 NULL。

看看官方文档中提供的几个例子:

long l;
char *s;
int s_len;
zval *param;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsz", &l, &s, &s_len, &param) == FAILURE) {
   return;
}


zval *obj;
double d = 0.5;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|d", &obj, my_ce, &d) == FAILURE) {
   return;
}


zval *obj;
zval *arr;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O!a", &obj, &arr) == FAILURE) {
   return;
}


zval *arr;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a/", &arr) == FAILURE) {
   return;
}


zval *z;
zend_bool b;
zval *r;
if (zend_parse_parameters(3, "zbr!", &z, &b, &r) == FAILURE) {
   return;
}

在接收参数时还有一个可用的函数zend_parse_parameters_ex,允许我们传入一些flags来控制解析参数的动作,使用方式如下所示:

int zend_parse_parameters_ex(int flags, int num_args TSRMLS_DC, char *type_spec, ...);

目前flags仅能传入ZEND_PARSE_PARAMS_QUIET这个值,表示函数不输出任何错误信息,如下面的示例:

long l1, l2, l3;
char *s;

if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                            ZEND_NUM_ARGS() TSRMLS_CC,
                            "lll", &l1, &l2, &l3) == SUCCESS) {
   
} else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET,
                                   ZEND_NUM_ARGS(), "s", &s, &s_len) == SUCCESS) {
   
} else {
   php_error(E_WARNING, "%s() takes either three long values or a string as argument",
             get_active_function_name(TSRMLS_C));
   return;
}

可变参数

由于PHP支持可变参数,所以在接收可变参数时,使用前面介绍的两个方法就不太合适,我们可以用zend_get_parameters_array_ex()来代替,如下面的示例:

zval **parameter_array[4];


argument_count = ZEND_NUM_ARGS();


if(argument_count < 2 || argument_count > 4)
{
    WRONG_PARAM_COUNT;
}


if(zend_get_parameters_array_ex(argument_count, parameter_array) != SUCCESS)
{
    WRONG_PARAM_COUNT;
}

本文我们介绍了在PHP扩展中接收参数,总共有三个函数:zend_parse_parameters、zend_parse_parameters_ex、zend_get_parameters_array_ex,关于参数解析其实还有更复杂的内容,下篇再介绍。

原文链接:,转发请注明来源!

发表评论