一、看一下一個擴展中的簡單代碼 php
ZEND_BEGIN_ARG_INFO(params_add_arginfo, 0) ZEND_ARG_INFO(0, a) ZEND_ARG_INFO(0, b) ZEND_END_ARG_INFO() PHP_FUNCTION(params_add) { long a,b; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &a, &b) == FALSE) { return; } RETURN_LONG(a+b); }
二、參數相關宏的定義 (Zend/zend_API.h) 數組
#define ZEND_ARG_INFO(pass_by_ref, name)\ { #name, sizeof(#name)-1, NULL, 0, 0, pass_by_ref, 0, 0 }, //聲明普通參數,能夠用來表示PHP中的int, float, double, string等基本數組類型 #define ZEND_ARG_PASS_INFO(pass_by_ref)\ { NULL, 0, NULL, 0, 0, pass_by_ref, 0, 0 }, //pass_by_ref爲1時,強制設置後續的參數爲引用類型 #define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null)\ { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, IS_OBJECT, pass_by_ref, allow_null, 0 }, //聲明對象類型的參數 #define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null)\ { #name, sizeof(#name)-1, NULL, 0, IS_ARRAY, pass_by_ref, allow_null, 0 }, //聲明數組類型的參數 #define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null)\ { #name, sizeof(#name)-1, NULL, 0, type_hint, pass_by_ref, allow_null, 0 }, #define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name)\ { #name, sizeof(#name)-1, NULL, 0, 0, pass_by_ref, 0, 1 }, #define ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args) \ static const zend_arg_info name[] = { \ { NULL, 0, NULL, required_num_args, 0, return_reference, 0, 0 }, #define ZEND_BEGIN_ARG_INFO(name, _unused) \ ZEND_BEGIN_ARG_INFO_EX(name, 0, ZEND_RETURN_VALUE, -1) #define ZEND_END_ARG_INFO() };
三、展開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) ui
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
五、zend_parse_parameters的參數 this
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。
看看官方文檔中提供的幾個例子:code
/* 取得一個長整數,一個字符串和它的長度,再取得一個 zval 值。 */ long l; char *s; int s_len; zval *param; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lsz", &l, &s, &s_len, ¶m) == FAILURE) { return; } /* 取得一個由 my_ce 所指定的類的一個對象,另外再取得一個可選的雙精度的浮點數。 */ zval *obj; double d = 0.5; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|d", &obj, my_ce, &d) == FAILURE) { return; } /* 取得一個對象或空值,再取得一個數組。若是傳遞進來一個空對象,則 obj 將被設置爲 NULL。*/ 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; } /* 僅取得前 3 個參數(這對可變參數的函數頗有用)。*/ 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這個值,表示函數不輸出任何錯誤信息,以下面的示例:blog
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) { /* manipulate longs */ } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "s", &s, &s_len) == SUCCESS) { /* manipulate string */ } else { php_error(E_WARNING, "%s() takes either three long values or a string as argument", get_active_function_name(TSRMLS_C)); return; }
可變參數three
因爲PHP支持可變參數,因此在接收可變參數時,使用前面介紹的兩個方法就不太合適,咱們能夠用zend_get_parameters_array_ex()來代替,以下面的示例:ip
zval **parameter_array[4]; /* 取得參數個數 */ argument_count = ZEND_NUM_ARGS(); /* 看一下參數個數是否知足咱們的要求:最少 2 個,最多 4個。 */ 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_NUM_ARGS來獲取參數個數,以下面的代碼:
if(ZEND_NUM_ARGS() != 2) { WRONG_PARAM_COUNT }
這段代碼使用宏WRONG_PARAM_COUNT拋出一個參數個數錯誤
七、更多的參數類型
#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類型參數的值