设为首页 收藏本站
查看: 1063|回复: 0

[经验分享] Linux 下PHP扩展开发系列:二. 一个典型的扩展开发

[复制链接]

尚未签到

发表于 2015-8-23 12:52:04 | 显示全部楼层 |阅读模式
  
  看完前言中所说的一些内容后,各位应该对PHP扩展开发有个笼统的了解了,可能有些人会觉得开发扩展很麻烦很复杂,实际上并非如此,这一篇我们就快速进入角色,开发出我们的第一个扩展。

  
  一、编译PHP
  开发之前还需要先准备好PHP源码并编译,过程如下:



tar -zxvf php-5.3.9.tar.gz
cd php-5.3.9
  我使用的是php5.3.9,解压后,我们进入了PHP源码目录,然后我们直接编译并增加php.ini:



./configure --prefix=/usr/local/webserver/php --enable-fastcgi --enable-fpm --enable-debug
make && make install
cp /home/soft/php-5.3.9/php.ini-development /usr/local/webserver/php/lib/php.ini
  编译完成,我没有静态编译其他扩展,但是开启了debug,这个后面会用到。然后修改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版本:
DSC0000.jpg
  OK,编译工作完成,让我们继续。
  
  二、典型开发流程
  一个典型的扩展开发流程如下图:
DSC0001.png
  
   三、扩展功能定义
  先定义我们要完成的扩展功能:
      该扩展只有一个功能,就是重写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的用法如下:



./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(设置骨架生成的目录,不设置该项则默认在ext/extname下)
--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=myip 即定义扩展的名称,而--proto=myip.pro则是定义扩展的函数原型,首先我们生成扩展函数原型文件:



vim myip.pro
  加入以下内容:



int ip2long32(string ip)
  这意味着我们的扩展中有一个函数,返回值为int型,输入为string。
  这时候执行以下命令生成扩展骨架:



./ext_skel --extname=myip --proto=myip.pro
  OK,这时候你会发现在当前PHP扩展目录下生成了一个子目录myip,进入myip看下:



cd myip
ll
  你会发现生成了一堆文件,如下图:
DSC0002.png
  此时我们就可以进行第二步了。
      2. 修改config.m4
  关于config.m4文件的功能,我们留到后面的文章中在详细进行说明,现在只说明要做什么。
  使用vim编辑config.m4:



vim config.m4
  将16至18行行首的dnl去掉,如下:
DSC0003.png
  具体这样做的原因在后面的文章中会说明,这边我们直接退出并保存config.m4,继续进入下一步。
      3. 编码
  重头戏来啦,终于可以进入myip.c中进行功能的编码了,一起欢呼下吧!



vim myip.c
  找到下图所示的位置:
DSC0004.png
  图中就是扩展骨架工具根据我们提供的函数原型生成的对应函数,此处有几个需要注意的地方:
  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, …);
  参数说明:




    •       num_args:传递给函数的参数个数。通常的做法是使用宏 ZEND_NUM_ARGS()。
    •       TSRMLS_CC:线程安全,总是传递TSRMLS_CC宏。 详解:http://www.54chen.com/php-tech/what-is-tsrmls_cc.html
    •       type_spec:第三个参数是一个字符串,指定了函数期望的参数类型
    •       ...:需要随参数值更新的变量列表]


    • type_spec是格式化字符串,其常见的含义如下:

      参数   代表着的类型

      b   Boolean

      l   Integer 整型

      d   Floating point 浮点型

      s   String 字符串

      r   Resource 资源

      a   Array 数组

      o   Object instance 对象

      O   Object instance of a specified type 特定类型的对象

      z   Non-specific zval 任意类型~

      Z   zval**类型

      f   表示函数、方法名称


  我们将该函数修改为如下内容:



PHP_FUNCTION(ip2long32)
{
char *ip = NULL;
int argc = ZEND_NUM_ARGS();
int ip_len;
if (zend_parse_parameters(argc TSRMLS_CC, "s", &ip, &ip_len) == FAILURE) {
return;
}
int32_t ip_int32;
unsigned char ip1, ip2, ip3, ip4;
sscanf(ip, "%hhu.%hhu.%hhu.%hhu", &ip1, &ip2, &ip3, &ip4);
ip_int32 = (int32_t)((ip1 << 24) | (ip2 << 16) | (ip3 << 8) | ip4);
RETURN_LONG(ip_int32);
}
  功能完成了,这边有个RETURN_LONG(ip_int32)比较特殊,这也是PHP内核提供的宏,用于返回值给PHP,具体说明如下:
  设置返回值并且结束函数        设置返回值             宏返回类型和参数
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. 编译



phpize
./configure --with-php-config=/usr/local/webserver/php/bin/php-config
make && make install
  不出意外的话编译完成后会有如下提示:



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



extension_dir = "/usr/local/webserver/php/lib/php/extensions/debug-non-zts-20090626/"
extension = myip.so
  退出保存,并重启php,如果是使用Phpfpm的话可以执行如下命令:



kill -USR2 `cat /usr/local/webserver/php/var/run/php-fpm.pid`
  看下扩展是否正常载入:



[iyunv@tm977 lib]# php -m|grep myip
myip
  说明已经正常载入了,最后我们测试下扩展函数吧!
  6. 测试



php -r "var_dump(ip2long32('192.168.1.1'));"
int(-1062731519)
php -r "var_dump(ip2long('192.168.1.1'));"  
int(3232235777)
  如上所示,ip2long32输出的是32位有符号整数,而ip2long输出的是64位无符号整数,大功告成!
  
  五、小结
      通过这一次的开发示例,是不是觉得其实开发一个扩展很简单?
      确实是的,但是也别高兴的太早了,实际上要开发出功能强大的扩展远不是这么简单的事情,后面的文章我会继续深入,一边开发一边了解更加复杂的PHP核心代码。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-102978-1-1.html 上篇帖子: 【原创】我是怎么从零开始教女同学进行php开发的(4) 下篇帖子: PHP爬虫(2)DOM处理
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表