前言
上一篇文章中主要写了如何写一个最简单的扩展,这一篇文章主要写如何实现简单的字符连接功能的扩展,类似php 中的’.’号,整个流程和上一篇文章是相同的,不同的是函数的实现方式,具体流程请参考 上一篇文章,这边文章主要讲核心功能,不涉及到整个生成扩展的过程。
核心代码
整个核心代码如下所示
1 PHP_FUNCTION(array_square_sum)
2 {
3 char * arg_one = NULL;
4 char * arg_two = NULL;
5 long arg_one_len;
6 long arg_two_len;
7 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &arg_one, &arg_one_len, &arg_two, &arg_two_len) == FAILURE)
8 {
9 return;
10 }
11 RETURN_STRINGL(strcat(arg_one, arg_two), (arg_one_len+arg_two_len), 1);
12 }
现在开始,分析代码,
首先:第3~6行代码主要是生命四个变量。
然后:第7行代码中zend_parse_parameters 函数是处理入参的函数。此函数的第一个参数是输入参数的个数,ZEND_NUM_ARGS()的作用就是获取入参的个数,TSRMLS_CC 的作用请参考究竟什么是TSRMLS_CC,第二个参数是指接收入参的格式,s代表是字符串,ss表示接收两个字符串,剩下的参数是把参数复制给哪些变量。注意当接收字符串的时候,需要在变量后面添加另外一个变量,接收字符串的长度。
最后: RETURN_STRINGL 是一个宏定义,标明是返回一个字符串,第一个参数是字符串,第二个参数是字符串的长度,第三个是值参数是否重复(个人理解,看了底层的代码,这个值传递为1需要重新分配内存,把字符串复制到新的内存中,如果是0,那么直接用旧的地址),具体的定义如下:
#define RETURN_STRINGL(s, l, duplicate) { RETVAL_STRINGL(s, l, duplicate); return; }
#define RETVAL_STRINGL(s, l, duplicate) ZVAL_STRINGL(return_value, s, l, duplicate)
#define ZVAL_STRINGL(z, s, l, duplicate) do {
const char *__s=(s); int __l=l;
zval *__z = (z);
Z_STRLEN_P(__z) = __l;
Z_STRVAL_P(__z) = (duplicate?estrndup(__s, __l):(char*)__s);
Z_TYPE_P(__z) = IS_STRING;
} while (0)
需要注意的是此处用的是RETURN_STRINGL 而不是RETURN_STRING是因为我们已经知道了新的字符串的长度,这样RETURN_STRINGL 要比RETURN_STRING 要少计算一次字符串的长度,效率要高一些。详情请参考ZVAL_STRING 和 ZVAL_STRINGL
参考文档
究竟什么是TSRMLS_CC
函数返回值
ZVAL_STRING 和 ZVAL_STRINGL