PHP 扩展开发的文章,我均已更新至《TIPI》(下面的博文可能已经过时,以 TIPI 上的内容为准)。
例如上篇中的
PHP_FUNCTION(confirm_helloworld_compiled) { char *arg = NULL; size_t arg_len, len; zend_string *strg; if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE) { return; } strg = strpprintf(0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "helloworld", arg); RETURN_STR(strg); }
ZEND_NUM_ARGS()
获取参数个数的宏
Zend/zend_API.h #define ZEND_NUM_ARGS() EX_NUM_ARGS()
zend_parse_parameters
解析参数,第一个参数是传递给函数的参数个数。通常的做法是传给它ZEND_NUM_ARGS()
。第二个参数是一个字符串,指定了函数期望的参数类型,后面紧跟着需要随参数值更新的变量列表。因为PHP采用松散的变量定义和动态的类型判断,这样做就使得把不同类型的参数转化为期望的类型成为可能。
ZEND_API int zend_parse_parameters(int num_args, const char *type_spec, ...)
下表列出了可能指定的类型。
类型指定符 | 对应的C类型 | 描述 |
l | long | 符号整数 |
d | double | 浮点数 |
s | char *, int | 二进制字符串,长度 |
b | zend_bool | 逻辑型(1或0) |
r | zval * | 资源(文件指针,数据库连接等) |
a | zval * | 联合数组 |
o | zval * | 任何类型的对象 |
O | zval * | 指定类型的对象。需要提供目标对象的类类型 |
z | zval * | 无任何操作的zval |
例如下面该表达式则是获取两个参数str
和n
,字符串的类型是s
,需要两个参数char *
字符串和int
长度;数字的类型l
,只需要一个参数
zend_parse_parameters(argc TSRMLS_CC, "sl", &str, &str_len, &n)
可变参数的原理
看其源码
ZEND_API int zend_parse_parameters(int num_args, const char *type_spec, ...) /* {{{ */ { va_list va; int retval; int flags = 0; va_start(va, type_spec); retval = zend_parse_va_args(num_args, type_spec, &va, flags); va_end(va); return retval; }
主要使用到了va_list
,va_start
,va_arg
和va_end
来获取可变个数的参数。
写了个代码片段,加深印象
#include <stdarg.h> #include <stdio.h> int zend_parse_parameters(int num_args, ...); int zend_parse_parameters2(int num_args, const char *type_spec, ...); int main() { zend_parse_parameters(3, 1, 2, 3); zend_parse_parameters2(4, "abcd", 1, 2, 3, 4); return 0; } int zend_parse_parameters(int num_args, ...) { va_list va; va_start(va, num_args); for (int i = 0; i < num_args; ++i) { printf("第 %d 个参数为: %d\n", i, va_arg(va, int)); } va_end(va); printf("===============\n"); return 0; } int zend_parse_parameters2(int num_args, const char *type_spec, ...) { va_list va; const char *spec_walk; char c; va_start(va, type_spec); for (spec_walk = type_spec; *spec_walk; spec_walk++) { c = *spec_walk; printf("参数类型为 %c 值为: %d\n", c, va_arg(va, int)); } va_end(va); printf("===============\n"); return 0; }
输出结果
第 0 个参数为: 1 第 1 个参数为: 2 第 2 个参数为: 3 =============== 参数类型为 a 值为: 1 参数类型为 b 值为: 2 参数类型为 c 值为: 3 参数类型为 d 值为: 4 ==================