参数传递

参数传递

1,创建一个新的扩展

./ext_skel --extname=params

2,修改config.m4,去掉没用的注释语句

cd params
vi config.m4

3,编写代码

vi php_params.h
#注释掉下面的代码
//PHP_FUNCTION(confirm_params_compiled);

vi params.c
#添加下面的代码
ZEND_BEGIN_ARG_INFO(params_add_arginfo, 0)
    ZEND_ARG_INFO(0, a)
    ZEND_ARG_INFO(0, b)
ZEND_END_ARG_INFO()

static PHP_FUNCTION(params_add) {
    long a,b;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &a, &b) == FAILURE) {
        return;
    }
    RETURN_LONG(a+b);
}

4,解释

#define ZEND_FE_END            { NULL, NULL, NULL, 0, 0 }

//参数相关宏的定义 (Zend/zend_API.h)
#define ZEND_ARG_INFO(pass_by_ref, name)                            { #name, sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref},

#define ZEND_ARG_PASS_INFO(pass_by_ref)                             { NULL, 0, NULL, 0, 0, 0, pass_by_ref},

#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, IS_OBJECT, allow_null, pass_by_ref},

#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, sizeof(#name)-1, NULL, 0, IS_ARRAY, allow_null, pass_by_ref},

#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, sizeof(#name)-1, NULL, 0, type_hint, allow_null, pass_by_ref},

#define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args)   \
static const zend_arg_info name[] = {                                                                       \
    { NULL, 0, NULL, required_num_args, 0, return_reference, pass_rest_by_reference},

#define ZEND_BEGIN_ARG_INFO(name, pass_rest_by_reference)   \
ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, ZEND_RETURN_VALUE, -1)  

#define ZEND_END_ARG_INFO()     };

//宏说明
ZEND_BEGIN_ARG_INFO(name, pass_rest_by_reference) //开始参数块定义,pass_rest_by_reference为1时,强制所有参数为引用类型
ZEND_END_ARG_INFO() //结束参数块定义
ZEND_ARG_INFO //声明普通参数,可以用来表示PHP中的int, float, double, string等基本数据类型
ZEND_ARG_OBJ_INFO //声明对象类型的参数
ZEND_ARG_ARRAY_INFO //声明数组类型的参数
ZEND_ARG_PASS_INFO(pass_by_ref)  //pass_by_ref为1时,强制设置后续的参数为引用类型 

//展开3中ZEND_BEGIN_ARG_INFO语句
static const zend_arg_info params_add_arginfo[] = {
    {NULL, 0, NULL, -1, 0, ZEND_RETURN_VALUE, 0},
    {a, sizeof(a)-1, NULL, 0, 0, 0, 0},
    {b, sizeof(b)-1, NULL, 0, 0, 0, 0},
};

//参数在zend中的定义(Zend/zend_compile.h)
#define ZEND_RETURN_VALUE               0
#define ZEND_RETURN_REFERENCE           1
typedef struct _zend_arg_info {
    const char *name; //参数的名称
    zend_uint name_len; //参数名称的长度
    char *class_name; //当参数类型为类时,指定类的名称
    zend_uint class_name_len; //类名称的长度
    zend_uchar type_hint; 
    zend_bool allow_null; //是否允许设置为null
    zend_bool pass_by_reference; //是否设置为引用,即使用&操作符
}

#define PHP_FUNCTION            ZEND_FUNCTION //函数的实现
#define ZEND_FUNCTION(name)             ZEND_NAMED_FUNCTION(ZEND_FN(name))
#define ZEND_NAMED_FUNCTION(name)       void name(INTERNAL_FUNCTION_PARAMETERS)
#define INTERNAL_FUNCTION_PARAMETERS int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used TSRMLS_DC

#define PHP_FE          ZEND_FE (php.h)//函数的定义,第一个参数是函数名,第二个参数是函数的参数的类型

(Zend/zend_API.h)
#define ZEND_FE(name, arg_info)                     ZEND_FENTRY(name, ZEND_FN(name), arg_info, 0)
#define ZEND_FENTRY(zend_name, name, arg_info, flags)   { #zend_name, name, arg_info, (zend_uint) (sizeof(arg_info)/sizeof(struct _zend_arg_info)-1), flags }, 

5,更多的参数类型

#define Z_TYPE_P //获取参数类型 IS_NULL|IS_BOOL|IS_LONG|IS_DOUBLE|IS_STRING|IS_ARRAY|IS_RESOURCE|IS_OBJECT
#define Z_BVAL_P //获取bool类型参数的值
#define Z_LVAL_P //获取long类型参数的值
#define Z_DVAL_P //获取float类型参数的值
#define Z_STRVAL_P //获取string类型参数的值
#define Z_STRLEN_P //获取string类型参数的长度
#define Z_ARRVAL_P //获取array类型参数的值
#define Z_RESVAL_P //获取resource类型参数的值
#define Z_OBJCE_P //获取object类型参数的值

6,zend_parse_parameters的参数

//数据类型
Boolean         b zend_bool      //布尔值
Long            l long           //长整数
Double          d double         //双精度浮点数
String          s char *, int    //符串 (也可能是空字节)和其长度
Resource        r zval*          // 资源, 保存在 zval*
Array           a zval*          //数组, 保存在 zval*
Object          o zval*          //任何类的)对象, 保存在 zval*
zval            z zval*          //实际的 zval*
zval            O zval*         //由class entry 指定的类的)对象, 保存在 zval*
HashTable       h HashTable*     //数组的哈希表
Function       f char *, int     //函数,方法名 (版本 > php5.1)
//操作符

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

//字符串类型参数
ZEND_BEGIN_ARG_INFO(params_str_arginfo, 0)
    ZEND_ARG_INFO(0, a)
    ZEND_ARG_INFO(0, b)
ZEND_END_ARG_INFO()

static PHP_FUNCTION(params_str) {
    char *str = "";
    int str_len = 0;
    long i = 0;
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sl", &str, &str_len, &i) == FAILURE) {
        return;
    }

    php_printf("string(%d) value:", str_len);
    PHPWRITE(str, str_len);
    php_printf("\n");

    php_printf("int(%d)\n", i);
    php_printf("\n");
}   

//调用上面的方法
<?php
$func = "params_str";
call_user_func($func, "hello world", 10);//传递了完整的变量
call_user_func($func);//没有传递变量

//结果
string(11) value:hello world
int(10)

string(0) value:
int(0)