全部博文(2759)
分类: PHP
2013-06-03 12:10:30
看完前言中所说的一些内容后,各位应该对PHP扩展开发有个笼统的了解了,可能有些人会觉得开发扩展很麻烦很复杂,实际上并非如此,这一篇我们就快速进入角色,开发出我们的第一个扩展。
一、编译PHP
开发之前还需要先准备好PHP源码并编译,过程如下:
tar -zxvf php-5.3.9.tar.gz cd php-5.3.9
我使用的是php5.3.9,解压后,我们进入了PHP源码目录,然后我们直接编译并增加php.ini:
点击(此处)折叠或打开
现在把PHP相关加入环境变量中,省去后面很多工作:
vim /root/.bash_profile
我是使用root,其他不同用户修改对应用户目录下的.bask_profile文件,在文件中的PATH后面加入:/usr/local/webserver/php/bin/,类似下面这样:
PATH=$PATH:$HOME/bin:/usr/local/webserver/php/bin/
环境变量设置好了,我们查看下PHP版本:
OK,编译工作完成,让我们继续。
二、典型开发流程
一个典型的扩展开发流程如下图:
三、扩展功能定义
先定义我们要完成的扩展功能:
该扩展只有一个功能,就是重写PHP的系统函数ip2long(),解决ip2long在32位与64位系统下值不同的问题(该问题是因为32位与64位的整形范围不同导致的,具体原因请google)。
我们新的ip2long固定返回32位有符号整数,范围-2147483648 到 2147483647,与32位系统相同。
我们的扩展名称为 myip,函数名为 ip2long32
扩展的功能与名称都OK了,现在按流程进行开发。
四、正式开发
1. 生成开发骨架
首先进入源码扩展目录:
cd /home/soft/php-5.3.9/ext
然后了解下PHP提供的扩展骨架工具ext_skel生成骨架,ext_skel的用法如下:
点击(此处)折叠或打开
vim myip.pro
加入以下内容:
int ip2long32(string ip)
这意味着我们的扩展中有一个函数,返回值为int型,输入为string。
这时候执行以下命令生成扩展骨架:
./ext_skel --extname=myip --proto=myip.pro
OK,这时候你会发现在当前PHP扩展目录下生成了一个子目录myip,进入myip看下:
cd myip
ll
你会发现生成了一堆文件,如下图:
此时我们就可以进行第二步了。
2. 修改config.m4
关于config.m4文件的功能,我们留到后面的文章中在详细进行说明,现在只说明要做什么。
使用vim编辑config.m4, 将16至18行行首的dnl去掉,如下:
具体这样做的原因在后面的文章中会说明,这边我们直接退出并保存config.m4,继续进入下一步。
3. 编码
重头戏来啦,终于可以进入myip.c中进行功能的编码了,一起欢呼下吧!
打开myip.c文件,找到下图所示的位置:
图中就是扩展骨架工具根据我们提供的函数原型生成的对应函数,此处有几个需要注意的地方:
1. PHP_FUNCTION:是PHP核心定义的一个宏,与ZEND_FUNCTION相同,用于定义扩展函数,实际生成的函数名称为zif_ip2long32。
2. zend_parse_parameters:由于PHP为弱类型语言,而C是强类型,因此需要使用该函数用于接收PHP传入的参数,并进行一定的类型转换,将PHP的变量转为C语言能够辨认的类型。
zend_parse_parameters函数的原型如下:
zend_parse_parameters(int num_args TSRMLS_CC, char *type_spec, …);
参数说明:
我们将该函数修改为如下内容:
点击(此处)折叠或打开
设置返回值并且结束函数 设置返回值 宏返回类型和参数
RETURN_LONG(l) RETVAL_LONG(l) 整数
RETURN_BOOL(b) RETVAL_BOOL(b) 布尔数(1或0)
RETURN_NULL() RETVAL_NULL() NULL
RETURN_DOUBLE(d) RETVAL_DOUBLE(d) 浮点数
RETURN_STRING(s, dup) RETVAL_STRING(s, dup) 字符串。如果dup为1,引擎会调用estrdup()重复s,使用拷贝。如果dup为0,就使用s
RETURN_STRINGL(s, l, dup) RETVAL_STRINGL(s, l, dup) 长度为l的字符串值。与上一个宏一样,但因为s的长度被指定,所以速度更快。
RETURN_TRUE RETVAL_TRUE 返回布尔值true。注意到这个宏没有括号。
RETURN_FALSE RETVAL_FALSE 返回布尔值false。注意到这个宏没有括号。
RETURN_RESOURCE(r) RETVAL_RESOURCE(r) 资源句柄。
编码完成了,保存并退出,然后我们可以开始编译了。
4. 编译
点击(此处)折叠或打开
Installing shared extensions: /usr/local/webserver/php/lib/php/extensions/debug-non-zts-20090626/
进入该目录看下是否已经有myip.so,有的话最后我们就可以修改php.ini载入该so文件
5. 修改php.ini
cd /usr/local/webserver/php/lib
vim php.ini
修改extension_dir,并加入 extension = myip.so
点击(此处)折叠或打开
退出保存,并重启php,如果是使用Phpfpm的话可以执行如下命令:
kill -USR2 `cat /usr/local/webserver/php/var/run/php-fpm.pid`
看下扩展是否正常载入:
[root@tm977 lib]# php -m|grep myip myip
说明已经正常载入了,最后我们测试下扩展函数吧!
6. 测试
点击(此处)折叠或打开
五、小结
通过这一次的开发示例,是不是觉得其实开发一个扩展很简单?
确实是的,但是也别高兴的太早了,实际上要开发出功能强大的扩展远不是这么简单的事情,后面的文章我会继续深入,一边开发一边了解更加复杂的PHP核心代码。