一、搭建骨干
PHP源码中提供了一个扩展开发工具 ext_skel,使用它能快速搭建一个扩展骨干。这个工具在 php-src/ext/ 目录下
./ext_skel --extname=hello
在控制台执行上面命令,会生成php-src/ext/hello 目录,hello就是扩展名。
目录结构如下
hello.c #是我们扩展的主要文件
config.m4 #m4是一个宏解释工具,用来生成我们扩展的makefile
php_hello.h #这个是我们扩展的头文件
tests/001.phpt #这个是个测试文件,使用的是单元测试,阶段测试
hello.php 模块测试文件,用于测试模块是否正确加载。
config.m4中包含了大量的dnl开头的行,表示是被注释掉的内容,删除不需要的内容,打开第10,11,12行,修改后的内容如下,
–enalle-hello 表示启用 hello模块
PHP_ARG_ENABLE(varstream, whether to enable varstream support,
[ --enable-hello Enable hello support])
if test "$PHP_HELLO" != "no"; then
PHP_NEW_EXTENSION(hello, hello.c, $ext_shared)
fi
在控制台执行 phpize 他会初始化PHP编译环境。
然后 ./configure & make
这样,模块就生成完毕。
此时,我们没有写任何代码,这个骨干里面包含了一个测试函数,
运行hello扩展目录下的 hello.php文件,它能测试模块是否已经被加载
php hello.php
二,导出HelloWorld方法
观察以下结构,这是扩展模板中默认的一个测试函数。
PHP_FUNCTION(confirm_hello_compiled)
{
char *arg = NULL;
int arg_len, len;
char *strg;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) {
return;
}
len = spprintf(&strg, 0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "hello", arg);
RETURN_STRINGL(strg, len, 0);
}
PHP_FUNCTION(confirm_hello_compiled) 表示定义了一个函数,confirm_hello_compiled为函数名。
现在,需要添加一个函数,输出Hello World,模仿以上,不难写出以下代码
PHP_FUNCTION(hello)
{
php_printf("Hello World");
}
php_printf 与C语言中 printf类似。
仅仅这些是不够的,虽然定义了需要的函数,但是没有任何一个地方说明了这个函数要干什么,如果要让用户空间能使用,至少需要导出才行。
在hello.c文件中,有如下结构,hello_module_entry,按照字面意思,就是hello模块的入口。
zend_module_entry hello_module_entry = {
STANDARD_MODULE_HEADER,
"hello",
hello_functions,
PHP_MINIT(hello),
PHP_MSHUTDOWN(hello),
PHP_RINIT(hello), /* Replace with NULL if there's nothing to do at request start */
PHP_RSHUTDOWN(hello), /* Replace with NULL if there's nothing to do at request end */
PHP_MINFO(hello),
PHP_HELLO_VERSION,
STANDARD_MODULE_PROPERTIES
};
第一个参数 STANDARD_MODULE_HEADER, 标准模块头,既然是标准,那就不要动这个。
第二个参数 “Hello”,就是模块的名字
第三个参数 hello_functions 就是模块中导出的方法。
申明如下:
const zend_function_entry hello_functions[] = {
PHP_FE(confirm_hello_compiled, NULL) /* For testing, remove later. */
PHP_FE_END /* Must be the last line in hello_functions[] */
};
可以看到,confirm_hello_compiled在其中,为了导出我们的方法hello,模仿以上写法即可,
const zend_function_entry hello_functions[] = {
PHP_FE(confirm_hello_compiled, NULL)
PHP_FE(hello, NULL)
PHP_FE_END /* Must be the last line in hello_functions[] */
};
后面的参数,暂时不用考虑,和hello模块,暂时没啥联系,后续再讲。
到这里,方法就对外可用了,于是 make ,可以在 hello/modules下面找到编译好的扩展。
三、使用
首先,需要PHP去加载创建的Hello模块
在php.ini中加入这个模块即可。
extention=xxxx/xxx/hello.so
修改配置文件后,需要重启web容器,可以在phpinfo()中找到hello模块信息。
既然模块已经导出了hello函数,那就和 PHP提供的普通函数一样使用就可以了。创建一个php脚本hello.php,如下
<?php
hello();
?>
在控制台执行 php hello.php 即可看到熟悉的 Hello World.