php扩展开发之”Hello World!”
最近在看《PHP扩展开发及内核应用》,书的内容不是特别多,但感觉都是精华,值得大家去一读的.这个系列的文章也是自己的读书的笔记或者一点心得吧,会把自己遇到的问题和踩过的坑都会提出来,大家可以引以为鉴,文章的不足和错误也请大家指出来.PHP做为现在最火的脚本语言之一,在Web方面更是当之无愧的王者,吸引大家使用PHP的原因有很多,而PHP的社区也是非常活跃和成功的,目前PHP7也预计要在十月份出来正式版本的.
其实PHP的扩展也是十分简单和便捷的,当然你在考虑用C/C++扩展你的PHP之前,建议还是考虑一下这么做是必须的或者说是必要的吗(用C/C++扩展你的PHP这篇文章开头关于扩展PHP的动机还是建议大家看一下的)?
现在我们将进入今天的整体写一个简单的整体,开发我们自己的PHP扩展.我下载的PHP版本是PHP5.6.10,也是最新版的,需要注意的是这个系列文章中的PHP都是PHP5以后版本的,之前的都是版本Zend engine都是1而PHP5之后Zend engine升级到2,因此如果你要是还在维护PHP5之前的版本,那么这个系列文章对您的帮助可能不是很大.
PHP源码提供了一个非常便捷的帮助大家创建自己的扩展工具,在ext目录下面大家可以看到它–“ext_skel”,在windows下面替代的工具是”ext_skel_win32.php”.
我们来看一下ext_skel有那些参数
./ext_skel --extname=module [--proto=file] [--stubs=file] [--xml[=file]] [--skel=dir] [--full-xml] [--no-help] --extname=module module is the name of your extension --proto=file file contains prototypes of functions to create --stubs=file generate only function stubs in file --xml generate xml documentation to be added to phpdoc-svn --skel=dir path to the skeleton directory --full-xml generate xml documentation for a self-contained extension(not yet implemented) --no-help don't try to be nice and create comments in the code and helper functions to test if the module compiled
这里面的extname是指定我们自己扩展的名称,proto是指定包含我们想要创建的函数文件,一般文件是def格式的.
这里我们创建自己的hellworld.def文件,内容如下
void hello_world(string name)
下面我们只需要执行下面的命令,就完成了我们扩展的大部分工作了.
./ext_skel --extname=hello_world --proto=helloworld.def Creating directory hello_world Creating basic files: config.m4 config.w32 .gitignore hello_world.c php_hello_world.h CREDITS EXPERIMENTAL tests/001.phpt hello_world.php [done]. To use your new extension, you will have to execute the following steps: 1. $ cd .. 2. $ vi ext/hello_world/config.m4 3. $ ./buildconf 4. $ ./configure --[with|enable]-hello_world 5. $ make 6. $ ./sapi/cli/php -f ext/hello_world/hello_world.php 7. $ vi ext/hello_world/hello_world.c 8. $ make Repeat steps 3-6 until you are satisfied with ext/hello_world/config.m4 and step 6 confirms that your module is compiled into PHP. Then, start writing code and repeat the last two steps as often as necessary.
上面的第1行是我们执行的命令,后面的脚本自动生成的内容,而我们开发扩展基本就按照这个流程来完成的.下面我们先去完成我们的hello_world函数去,然后我们的扩展工作基本就完成了.
进入ext/hello_world目录,编辑hello_world.c文件,这是我们扩展的主要文件了,只要我们的扩展内容不是特别多,我们可以完全把函数放在这里面的来完成.找到系统帮我们生成的代码中的”PHP_FUNCTION(hello_world)”,然后我们在此完成我们的hello_world功能.
PHP_FUNCTION(hello_world) { char *name = NULL; int argc = ZEND_NUM_ARGS(); int name_len; if (zend_parse_parameters(argc TSRMLS_CC, "s", &name, &name_len) == FAILURE) return; //php_error(E_WARNING, "hello_world: not yet implemented"); php_printf("Hello World!\n"); php_printf("Hello %s!\n",name); RETURN_NULL(); }
其实我们就动了4行代码,注释掉php_error,然后和后面加上的3行代码.至此我们的功能就全部实现了.剩下就是按照扩展了.但是如果你去hello_world.c文件里面代码,你会发现ext_skel帮助我们生成很多代码,里面还是有一些东西是需要我们注意一下.
我们来看一下紧跟着hello_world函数的代码.
/* {{{ hello_world_functions[] * * Every user visible function must have an entry in hello_world_functions[]. */ const zend_function_entry hello_world_functions[] = { PHP_FE(confirm_hello_world_compiled, NULL) /* For testing, remove later. */ PHP_FE(hello_world, NULL) PHP_FE_END /* Must be the last line in hello_world_functions[] */ }; /* }}} */ /* {{{ hello_world_module_entry */ zend_module_entry hello_world_module_entry = { STANDARD_MODULE_HEADER, "hello_world", hello_world_functions, PHP_MINIT(hello_world), PHP_MSHUTDOWN(hello_world), PHP_RINIT(hello_world), /* Replace with NULL if there's nothing to do at request start */ PHP_RSHUTDOWN(hello_world), /* Replace with NULL if there's nothing to do at request end */ PHP_MINFO(hello_world), PHP_HELLO_WORLD_VERSION, STANDARD_MODULE_PROPERTIES }; /* }}} */
“const zend_function_entry hello_world_functions”这个数组定义了我们扩展里面包含那些函数,当初我没有使用ext_skel的proto参数生成,就没有把我自己写的函数加入到hello_world_functions.导致我在编译安装完扩展以后,在PHP代码里面使用我在扩展里面写的函数的时候,就一直报错”Call to undefined function”,还是google好久才找到问题所在.所以如果你不是用ext_skel的proto参数生成的,在编译安装之前要注意一下这里.下面"zend_module_entry hello_world_module_entry "定义是hello_world模块.关于这些内容具体解释可以参考《PHP扩展开发与内核应用》第5章1节和4节的一些内容.
配置config.m4
现在如果我们要安装我们的扩展,还需要配置扩展目录下面的config.m4文件啦.
dnl PHP_ARG_WITH(hello_world, for hello_world support, dnl Make sure that the comment is aligned: dnl [ --with-hello_world Include hello_world support]) dnl Otherwise use enable: PHP_ARG_ENABLE(hello_world, whether to enable hello_world support, dnl Make sure that the comment is aligned: [ --enable-hello_world Enable hello_world support])
dnl是m4文件的注释, 根据需要去掉相应的注释,PHP_ARG_WITH是我们在configure时”–with-xx”,此种方式一般依赖一些库的.而PHP_ARG_ENABLE是”–enable-xx”的方式,一般都是可以单独编译安装的,不依赖任何其他库支持的.我们这里选择PHP_ARG_ENABLE即可.
安装扩展
下面就是编译安装扩展了,如果你做过相关的工作就可以跳过这个小节的直接动手去尝试了.
phpize ./configure make sudo make install
在你的php.ini最后加上
extension=hello_world.so //如果你的扩展是zend的,那需要改成zend_extension即可
重启你的apache或者php-fpm进行测试即可了.
测试扩展
编写一个测试的php脚本进行一下测试,查看我们的扩展是否安装成功.
<?php hello_world("king"); ?> //最终输出如下,说明我们的扩展已经正常工作了 Hello World! Hello king!
我们的hello world扩展开发也完成了.
近期评论