7.2 函数的参数

在前面的章节中我们已经介绍过arg info了,下面我们看一下如何通过其实现类型绑定,但这个特性只能在Zend Engine 2也就是PHP5中使用。 让我们再回顾一下ZE2’s argument info结构。每一个arg info结构的声明都是通过ZENDBEGIN_ARG_INFO()或者ZEND_BEGIN_ARG_INFO_EX()宏函数开始的,然后紧跟着几行ZEND_ARG*INFO()宏函数,最终以ZEND_END_ARG_INFO()宏函数结束。每个宏的基本作用我们可以在第6章的最后一节看到。如果我们想重写一下PHP语言中的count()函数,可以:

  1. ZEND_FUNCTION(sample_count_array)
  2. {
  3. zval *arr;
  4. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a",&arr) == FAILURE)
  5. {
  6. RETURN_NULL();
  7. }
  8. RETURN_LONG(zend_hash_num_elements(Z_ARRVAL_P(arr)));
  9. }

zend_parse_parameters()本身可以保证传递过来的参数是一个数组。但是如果我们通过zend_get_parameter()函数来接收参数的话就没这么幸运了,需要我们自己进行类型校对。如果想让内核自动完成类型校对,便需要arg_info上场了:

  1. ZEND_BEGIN_ARG_INFO(php_sample_array_arginfo, 0)
  2. ZEND_ARG_ARRAY_INFO(0, arr, 0)
  3. ZEND_END_ARG_INFO()
  4. ....
  5. PHP_FE(sample_count_array, php_sample_array_arginfo)
  6. ....

这样我们便把类型校对的工作交给了Zend Engine,是不是有种如释重负的感觉!You’ve also given your argument a name so that the generated error messages can be more meaningful to script writers attempting to use your API. 我们同样可以对参数中的对象进行校验,限制其是继承自某个类或者实现了某个接口等等。

  1. ZEND_BEGIN_ARG_INFO(php_sample_class_arginfo, 0)
  2. ZEND_ARG_OBJ_INFO(1, obj, stdClass, 0)
  3. ZEND_END_ARG_INFO()

需要注意的是,此时第一个参数的值是数字1,代表着以引用的方式传递。其实这个参数对于对象来说几乎没用,因为ZE2中所有的对象在当作函数参数的时候都是默认以引用的形式传递的。但是我们又必须把这个参数设置为数字1,除非你不想让你的扩展与PHP4兼容。在PHP4中,对象是传递的一个完整Copy,而非通过引用。

  1. 对于数组和对象参数,不要忘记最后的允许为NULL的参数。更多的信息请参考第6章最后一节的有关叙述。

通过arg info的方式来实现类型绑定的功能只对ZE2有效,也就是PHP5+。如果你想在PHP4上实现相应的功能,那需要用 zend_get_parameters()函数来接收参数,然后通过Z_TYPE_P()宏函数来检测参数的类型或者通过convert_to_type()函数进行类型转换。