1 前言
- 主要目的让大家了解一下怎么做PHP语言的扩展,仍然以上次叙述的Perl的扩展的例子——获得IP来源地址为例。
2 前提条件
- 假设你已经拥有了 LAMP (Linux+Apache+Mysql+PHP的缩写),并假设其安装路径分别是:
Apache:/usr/local/apache
Mysql:/usr/local/mysql
PHP:/usr/local/php
- 目前所叙述的实例可能与 mysql 没有太多的关系,所以无关紧要,但是 PHP 是必须安装的;
- 另外,需要 PHP 的源码,如果你没有,可以去 http://www.php.net 获取 PHP 源码,其源码路径位:
PHPSrc:/usr/local/php/src
- 末了说句,本实例完全在 Linux 64 位平台下演示,若有出入,可以随时联系笔者。
3 流程及步骤
- 其实制作PHP扩展非常简单, ext_skel 命令的帮助已说明得非常详细,如下所示:
[Cnangel@localhost ~]$cd /usr/local/php/src/ext
[Cnangel@localhost ext]$ext_skel --help
./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-cvs
--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
- 尝试着创建一个扩展 getaddress :
[Cnangel@localhost ext]$ext_skel --extname=getaddress
Creating directory getaddress
Creating basic files: config.m4 config.w32 .cvsignore getaddress.c php_getaddress.h CREDITS EXPERIMENTAL tests/001.phpt getaddress.php [done].
To use your new extension, you will have to execute the following steps:
1. $ cd ..
2. $ vi ext/getaddress/config.m4
3. $ ./buildconf
4. $ ./configure --[with|enable]-getaddress
5. $ make
6. $ ./php -f ext/getaddress/getaddress.php
7. $ vi ext/getaddress/getaddress.c
8. $ make
Repeat steps 3-6 until you are satisfied with ext/getaddress/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.
- 上面的后续的帮助步骤已经说得比较清楚,一共 8 个步骤;
4 详细过程描述
4.1 建立扩展目录
- 方便的 ext_skel 命令能帮助建立一个扩展模型 getaddress ,系统会自动建立一个 getaddress 目录,其文件会相应的生成在 getaddress 目录内;
4.2 描述及编辑config.m4
- 用 ext_skel 建立的目录里面一般有 config.m4 这个文件,这里面有一些基础的宏定义:
- dnl 是注释;
- PHP_ARG_WITH 或者 PHP_ARG_ENABLE 指定了PHP扩展模块的工作方式;
- PHP_REQUIRE_CXX 用于指定这个扩展用到了C++;
- PHP_ADD_INCLUDE 指定PHP扩展模块用到的头文件目录;
- PHP_CHECK_LIBRARY 指定PHP扩展模块PHP_ADD_LIBRARY_WITH_PATH定义以及库连接错误信息等;
- PHP_SUBST 用于说明这个扩展编译成动态链接库的形式;
- PHP_NEW_EXTENSION 用于指定有哪些源文件应该被编译,文件和文件之间用空格隔开;
- 这里指定PHP扩展模块的工作方式为 PHP_ARG_ENABLE ,需要修改config.m4文件为:
[Cnangel@localhost getaddress]vim config.m4找到里面有类似几行:
dnl PHP_ARG_WITH(getaddress, for getaddress support,修改成:
dnl Make sure that the comment is aligned:
dnl [ --with-getaddress Include getaddress support])
dnl Otherwise use enable:
dnl PHP_ARG_ENABLE(getaddress, whether to enable getaddress support,
dnl Make sure that the comment is aligned:
dnl [ --enable-getaddress Enable getaddress support])
dnl PHP_ARG_WITH(getaddress, for getaddress support,
dnl Make sure that the comment is aligned:
dnl [ --with-getaddress Include getaddress support])
dnl Otherwise use enable:
PHP_ARG_ENABLE(getaddress, whether to enable getaddress support,
Make sure that the comment is aligned:
[ --enable-getaddress Enable getaddress support])
- 除了修改 config.m4 外,还需要修改的文件有 getaddress.c 、 php_getaddress.h 两个文件,下面会说到该文件的修改。
4.3 创建configure文件
- 源码修改:进入源代码根目录,使用工具 buildconf 创建 configure 文件,其命令如下:
[Cnangel@localhost getaddress]cd /usr/local/php/src
[Cnangel@localhost src]./buildconf
- 扩展修改:进入扩展目录,使用工具 phpize 创建 configure 文件,其目录如下:
[Cnangel@localhost getaddress]/usr/local/php/bin/phpize
Configuring for:
PHP Api Version: 20041225
Zend Module Api No: 20060613
Zend Extension Api No: 220060519
4.4 创建Makefile文件
- 上个步骤中创建了 configure 文件,记住,一般在类unix系统中, configure 文件是一个可执行文件,用来创建编译过程中所用到的make命令所需要的Makefile文件,其创建过程如下:
./configure --enable-getaddress --with-apxs=/usr/local/apache/bin/apxs --with-php-config=/usr/local/php/bin/php-config
- 注意,如果你写的扩展与apache有关,则需要关联apxs,产生apache的modules。
4.5 编译过程
- 编译过程是一个调试过程,出现错误了需要检查 config.m4 、 getaddress.c 、 php_getaddress.h 这几个文件是否编写正确,编译的过程十分简单,命令如下:
make
4.6 安装扩展模块
- 安装扩展模块一般有两种安装,一种是直接:
make install
- 结果会安装到: /usr/local/php/lib/php/extensions/no-debug-non-zts-20060613/ 目录,然后在 php.ini 里面通过 extension_dir 将该目录设置为php的扩展目录,并在php.ini中打开这个扩展:
extension=getaddress.so
- 另外一种是直接复制。一般经过编译过程这个步骤后,会在 getaddress 目录下生成一个目录: modules ,该目录下面有一个已经编译好的.so文件,如果是静态编译,可能是.a或.la;把该文件复制到一个目录下,比如: /usr/loca/php/ext/ ,然后直接调用函数 dl 来调用其 api。
4.7 运行测试
- getaddress 目录下有一个 getaddress.php 文件专门用来测试你的扩展模块是否正确运行,该文件即可以作为 CGI 来运行又可以当作脚本执行,命令如下:
[Cnangel@localhost getaddress]php -f getaddress.php
Functions available in the test extension:
confirm_getaddress_compiled
Congratulations! You have successfully modified ext/getaddress/config.m4. Module getaddress is now compiled into PHP.
4.8 增添PHP扩展模块函数
- 上述讲了这么多,这节才是最主要的。PHP扩展模块主要有三个方面的作用:
- 增加PHP基础函数没有的功能或更加 OOP(Object Oriented Programming) 的思想供工程调用;
- PHP的扩展一般是汇编、C/C++等编译性语言缩写,二进制运行消耗时间比解释性语言实现同样的功能少得多;
- 由于PHP扩展一般是二进制的,所以一般来说不开源,很方便的保护了版权,能够进行商业运用。
- 默认的 getaddress.c 中, zend_function_entry 是导出函数列表, zend_module_entry 描述了模块的信息。
- 编写代码应该注意:
- 如果是C++开发,记住把getaddress.c的后缀改为cpp,并用extern "C"来把c相关代码包起来;
5 Bugs
- 在64位机器上和32位机器上会出现很大的差异,主要在QQWry.c文件;
- 多个引用php函数会出现corp dump情况,具体原因还未查清;
6 实例代码
- 注意,修复一处Bug:将
Z_STRVAL_P(file) == NULL代替
Z_STRLEN_P(file) == 0
7 总结
- 由于作者对C指针运用不太熟练,所以在操作指针时,往往会出现corp dump,这方面有待加强;
- 就PHP扩展来说,涵盖的面比较广,需要丰富的知识面做铺垫才能做好一个优秀的扩展。
参考:
http://tech.ddvip.com/2009-09/1252583445132022.html
作者:jackxiang@向东博客 专注WEB应用 构架之美 --- 构架之美,在于尽态极妍 | 应用之美,在于药到病除
地址:http://jackxiang.com/post/1104/
版权所有。转载时必须以链接形式注明作者和原始出处及本声明!
最后编辑: jackxiang 编辑于2009-10-23 21:43
评论列表