上一节简单的演示了一遍PHP7扩展开发和编译安装的流程,本文对上一节中的函数例子进行详细解释,帮助理解扩展开发。
开始之前
如果不熟悉扩展开发的流程,请先浏览: Linux下PHP7扩展开发入门教程1-扩展开发流程
代码结构详解
编写扩展中的函数,一般情况下,函数结构如下:
1 | /* {{{ 注释中写函数原型,包括函数名、参数、返回值 |
下面是生成扩展开发的骨架时的第二个函数例子:
1 | // 以下注释是函数的原型,即:函数learn_ext_test2有一个string类型的可选参数,返回值也是string。 |
如果对C语言不熟悉的话,小朋友们可能会有很多问号:
下面这段代码是什么语法?为什么后面没有分号?
1
2
3
4
5
6ZEND_PARSE_PARAMETERS_START(0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_STRING(var, var_len)
ZEND_PARSE_PARAMETERS_END();
// .....
RETURN_STR(retval);答:上面这些大写的“函数”其实是C语言中的宏定义,编译之前会进行“宏替换”,即把它们替换成相应的C语言代码。
在编译时,
ZEND_PARSE_PARAMETERS_START
会被替换成检查参数个数的代码,如果调用php函数时参数个数不对,则会抛出异常。如果感兴趣,可以查看一下宏定义,
ZEND_PARSE_PARAMETERS_START
的定义在Zend/zend_API.h :1139
,不同php版本代码位置会有差异。ZEND_PARSE_PARAMETERS_START(0, 1)
的含义是什么?其中的参数0和1是什么意思?
答:ZEND_PARSE_PARAMETERS_START
有两个参数,它们分别是参数个数的最小值和最大值。因为编写的php函数只有1个参数并且是可选的,所以参数的个数是0~1。为什么
Z_PARAM_STRING(var, var_len)
要传参数var_len
进去?
答:Z_PARAM_STRING
也是一个宏定义,它有两个参数,第一个参数var
是一个char
类型的指针。
调用php函数时,如果没有传入参数,它的就是默认值”World”;如果传入了参数,var
就会被修改为实际传入的字符串。同理,如果传入了参数,var_len
也会被修改为实参的长度。为什么最后函数返回是
RETURN_STR(retval)
,而不是return retval
?
答:跟ZEND_PARSE_PARAMETERS_START
类似,RETURN_STR
仍然是一个宏定义,最后代码会被替换为:- 把
retval
转换为字符串; return retval
。
- 把
为什么在其它教程中,获取参数的写法不一样?
答:这是PHP7的新写法,叫做FAST_ZPP。以count
函数为例,PHP7之前的写法:1
2
3
4
5
6
7
8
9
10PHP_FUNCTION(count)
{
zval *array;
long mode = COUNT_NORMAL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &mode) == FAILURE) {
return;
}
....
}PHP7的FAST_ZPP写法:
1
2
3
4
5
6
7
8
9
10
11
12PHP_FUNCTION(count)
{
zval *array;
zend_long mode = COUNT_NORMAL;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_ZVAL(array)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(mode)
ZEND_PARSE_PARAMETERS_END();
...
}PHP7之前的语法依然可用,新版语法更加易于理解,且性能更高。
参数信息
写完函数后,还要写函数的参数信息ZEND_ARG_INFO
,指明参数是否为引用,参数信息可以用于参数类型提示和反射等。
一般格式如下:
1 | /* {{{ arginfo |
下一步
终于要开始写代码了!
进入第3篇:Linux下PHP7扩展开发入门教程3: 编写第一个函数