c写php扩展传参学习记录

最简单的获取函数调用者传递过来的参数便是使用zend_parse_parameters()函数。

zend_parse_parameters()函数的前几个参数我们直接用内核里宏来生成便可以了,形式为:ZEND_NUM_ARGS() TSRMLS_CC,注意两者之间有个空格,但是没有逗号。从名字可以看出,ZEND_NUM_ARGS()代表这参数的个数。

紧接着需要传递个zend_parse_parameters()函数的参数是一个用于格式化的字符串,就像printf的第一个参数一样。下面表示了最常用的几个符号。

类型指定符对应的C类型描述
llong符号整数
ddouble浮点数
schar *, int二进制字符串,长度
bzend_bool逻辑型(1或0)
rzval *资源(文件指针,数据库连接等)
azval *联合数组
ozval *任何类型的对象
Ozval *指定类型的对象。需要提供目标对象的类类型
zzval *无任何操作的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<argc; i++)
    {
        php_var_dump(args[i], 1 TSRMLS_CC);
    }
    efree(args);        //稀放内存
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值