前一节对扩展中的函数结构进行了详细解释,遗憾的是没有亲自编写代码实现扩展。这一节将编码实现一个函数int array_max(array $arr)
。
开始之前
本文是PHP扩展开发系列教程第3篇:
- Linux下PHP7扩展开发入门教程1: 扩展开发流程
- Linux下PHP7扩展开发入门教程2: 函数结构详解
- Linux下PHP7扩展开发入门教程3: 编写第一个函数
如果没有浏览过前面的文章,可以先浏览。
编写第一个函数
目标
用扩展编写一个函数,获取一个整数数组的最大值(类似max()函数)。如果用PHP来编写,代码如下:
1 |
|
接下来,用扩展的方式实现这个函数
建立扩展开发骨架
进入源代码的扩展目录,调用脚本创建一个array_util
扩展:
1 | cd php-7.4.4/ext/ |
编写array_max函数
首先把
array_util.c
中自动生成的两个函数array_util_test1
和array_util_test2
删除;要编写的函数
array_max
有1个必选参数,类型是数组,返回值是一个整数。函数原型如下:1
int array_max( array $max)
编写array_max函数,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30/* {{{ int array_max( array $max)
*/
PHP_FUNCTION(array_max){
zval *arr; // 传入的数组参数
zval *entry; // 用于数组循环时保存每一个元素
zend_long current_num, max_num = 0;
zend_ulong num_idx; // 数组下标(类型)
zend_string *str_idx; // 数组下班(字符串类型)
// 参数只有一个,是必选的,所以ZEND_PARSE_PARAMETERS_START的参数是1, 1
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_ARRAY(arr) // 参数,类型是数组
ZEND_PARSE_PARAMETERS_END();
// 数组循环,参数分别是:数组、下标(数字类型)、下标(字符串类型)、数组元素
// arr是zval*类型的,要用Z_ARRVAL_P()访问数组的值
ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(arr), num_idx, str_idx, entry){
// 同理,entry是zval*类型的,用Z_LVAL_P()来获取zend_long类型的数值
current_num = Z_LVAL_P(entry);
if(num_idx == 0) {
max_num = current_num;
}else{
if(current_num > max_num){
max_num = current_num;
}
}
}ZEND_HASH_FOREACH_END(); // 循环结束
RETURN_LONG(max_num); // 返回一个整数
}定义函数参数信息。找到
arginfo
片段,改为:1
2
3
4
5
6/* {{{ arginfo
*/
ZEND_BEGIN_ARG_INFO(arginfo_array_max, 0)
ZEND_ARG_INFO(0, arr)
ZEND_END_ARG_INFO()
/* }}} */ZEND_BEGIN_ARG_INFO
的第一个参数是arginfo_函数名
,第二个参数还没用到。
ZEND_ARG_INFO
的第一个参数指明参数类型是否是引用,第二个是参数名称。定义扩展的函数列表。找到
array_util_functions
片段,改为:1
2
3
4
5
6
7/* {{{ array_util_functions[]
*/
static const zend_function_entry array_util_functions[] = {
PHP_FE(array_max, arginfo_array_max)
PHP_FE_END
};
/* }}} */编译测试
在扩展目录
ext/array_util
下运行make
命令编译。1
make
编译后在modules目录会生成一个
array_util.so
文件。修改php.ini,添加
array_util
扩展:1
extension=/path/to/array_util.so
编写测试脚本:
1
2
3
4
5
var_dump(array_max([1,2,5,7,4]));
var_dump(array_max([1,2,3,4]));
var_dump(array_max([4]));
var_dump(array_max([]));执行脚本:
1
2
3
4
5root@ed78d89e5328:~/php-7.4.4/ext/array_util# php test.php
int(7)
int(4)
int(4)
int(0)