# 7.1 函数的参数 最简单的获取函数调用者传递过来的参数便是使用zend_parse_parameters()函数。 zend_parse_parameters()函数的前几个参数我们直接用内核里宏来生成便可以了,形式为:ZEND_NUM_ARGS() TSRMLS_CC,注意两者之间有个空格,但是没有逗号。从名字可以看出,ZEND_NUM_ARGS()代表着参数的个数。 紧接着需要传递给zend_parse_parameters()函数的参数是一个用于格式化的字符串,就像printf的第一个参数一样。下面表示了最常用的几个符号。 ````c type_spec是格式化字符串,其常见的含义如下: 参数 代表着的类型 b Boolean l Integer 整型 d Floating point 浮点型 s String 字符串 r Resource 资源 a Array 数组 o Object instance 对象 O Object instance of a specified type 特定类型的对象 z Non-specific zval 任意类型~ Z zval**类型 f 表示函数、方法名称,PHP5.1里貌似木有... ... ```` 这个函数就像printf()函数一样,后面的参数是与格式化字符串里的格式一一对应的。一些基础类型的数据会直接映射成C语言里的类型。 ````c ZEND_FUNCTION(sample_getlong) { long foo; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,"l", &foo) == FAILURE) { RETURN_NULL(); } php_printf("The integer value of the parameter is: %ld\n", foo); RETURN_TRUE; } ```` 一般来说,int和long这两种数据类型的数据往往是相同的,但也有例外情况。所以我们不应改把long的数组放在一个int里,尤其是在64位平台里,那将引发一些不容易排查的Bug。所以通过zend_parse_parameter()函数接收参数时,我们应该使用内核约定好的那些类型的变量作为载体。 ````c 参数 对应C里的数据类型 b zend_bool l long d double s char*, int 前者接收指针,后者接收长度 r zval* a zval* o zval* O zval*, zend_class_entry* z zval* Z zval** ```` 注意,所有的PHP语言中的复合类型参数都需要zval*类型来作为载体,因为它们都是内核自定义的一些数据结构。我们一定要确认参数和载体的类型一致,如果需要,它可以进行类型转换,比如把array转换成stdClass对象。 s和O(字母大写欧)类型需要单独说一些,因为它们都需要两个载体。我们将在接下来的章节里了解php中对象的具体实现。这样我们改写一下我们在第五章定义的一个函数: ````php 如果传递给函数的参数数量小于zend_parse_parameters()要接收的参数数量,它便会执行失败,并返回FAILURE。 如果我们需要接收多个参数,可以直接在zend_parse_paramenters()的参数里罗列接收载体便可以了,如: ````php 注意zend_get_parameters_ex不需要ZEND_NUM_ARGS()作为参数,因为它是在是在后期加入的,那个参数已经不再需要了。 上面例子中还使用了WRONG_PARAM_COUNT宏,它的功能是抛出一个E_WARNING级别的错误信息,并自动return。 ### 可变参数 有两种其它的zend_get_parameter_**函数,专门用来解决参数很多或者无法提前知道参数数目的问题。想一下php语言中var_dump()函数的用法,我们可以向其传递任意数量的参数,它在内核中的实现其实是这样的: ````c ZEND_FUNCTION(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; } for (i=0; i) * 7.2 [Arg Info 与类型绑定](<7.2.md>)