搜索

php扩展开发

一. 摘要
PHP Extension是扩展PHP的主要手段,如数据库访问,序列化,或者远程过程调用,使用过PHP的人,其实都使用过PHP Extension,PHP里面很多的函数也是通过扩展实现的,而在PHP源码中包含了几十个扩展,PECL仓库中也提供了上百个扩展,所以只要使用 PHP开发,就不可避免的要开发PHP Extension。本文会用图文并茂的方式一步一步为大家介绍如何开发一个PHP Extension。

开发环境:Ubuntu 10.10,PHP 5.3.5,有一个可运行PHP的Web服务器(Nginx或Apache)
要求:了解C语言基础,了解PHP编程
需求:开发一个名为fetion_echo的Extension,只有一个简单的say_goodbye()函数,输入一个字符串,该函数返回"Goodbye xxx"。

开发PHP Extension的过程基本可以分为如下几步:?
1. 生成扩展框架?
2. Unix Build System配置?
3. 编写phpinfo()回调函数?
4. 编写核心代码?
5. 配置、编译?
6. 配置php.ini

二. 生成扩展框架
下载PHP源代码,我使用的是PHP 5.3.5。进入PHP源代码目录可以看到有个ext目录,这里是和PHP Extension有关,使用ls命令查看,可以看到很多已经存在的PHP Extension,如pdo_mysql,json等,如图1所示:

注意在该目录下有一个ext_skel脚本文件,接下来我们将会用它来生成Linux环境下PHP Extension代码框架,而ext_skel_win32.php是windows下的生成脚本。ext_skel完整的命令格式为:
./ext_skel --extname=module [--proto=file] [--stubs=file] [--xml[=file]]<br> [--skel=dir] [--full-xml] [--no-help]
对其中的参数解释如下:?
--extname:参数指定了Extension的名字?
--no-help:指定在生成的代码框架中不加入注释等,除非我们对于开发PHP Extension非常有经验,否则还是不要指定该参数。其他的参数我们暂时可以不用考虑。

接下来在ext目录下输入如下命令:
$ ./ext_skel --extname=fetion_echo
再次使用ls命令查看ext目录,可以看到多了一个名为fetion_echo的目录,进入该目录可以看到ext_skel已经为我们建立好了PHP Extension的基本框架,如图2所示:

在这里有几个比较重要的文件,我们需要介绍一下:?
config.m4:Linux下的Build System配置文件,会使用它来生成configure文件和makefile。?
php_fetion_echo.h:扩展模块的头文件。?
fetion_echo.c:扩展模块的主程序文件,如果我们的扩展模块中有多个函数,最终所有的函数入口都在该文件中。

三. Unix Build System配置
config.m4文件告诉Unix Build System我们的扩展支持什么configure选项,使用Emacs或者vim打开该文件,大家可以看到一堆不认识的配置,不过不用担心,因为该文件 中以"dnl"开头的都是注释,暂时不用考虑。我们能用到只有下面几行:
dnl If your extension references something external, use with:<br> dnl PHP_ARG_WITH(fetion_echo, for fetion_echo support,<br> dnl Make sure that the comment is aligned:<br> dnl [ --with-fetion_echo Include fetion_echo support])<br> dnl Otherwise use enable:<br><span style="color: #ff0000;">dnl PHP_ARG_ENABLE(fetion_echo, whether to enable fetion_echo support,<br> dnl Make sure that the comment is aligned:<br> dnl [ --enable-fetion_echo Enable fetion_echo support])</span>
其实大家都能看明白,如果扩展使用了一些外部的引用,就使用下面的三行,否则使用最后面的三行,由于我们只是开发一个简单的echo扩展,没有使用任何外部引用,只要取消掉最后三行的注释就行:
PHP_ARG_ENABLE(fetion_echo, whether to enable fetion_echo support,<br> Make sure that the comment is aligned:<br> [ --enable-fetion_echo Enable fetion_echo support])<span class="Apple-converted-space">?</span>
保存退出,至此配置文件就完成了。

四. 分析PHP Extension核心代码
为了下面更好的介绍,这里先简单的介绍PHP Extension核心代码,打开fetion_echo.c文件,可以看到如下一段代码:
/* {{{ fetion_echo_module_entry */<br> zend_module_entry fetion_echo_module_entry = {<br> #if ZEND_MODULE_API_NO >= 20010901<br> STANDARD_MODULE_HEADER,<br> #endif<br> "fetion_echo",<br> fetion_echo_functions,<br> PHP_MINIT(fetion_echo),<br> PHP_MSHUTDOWN(fetion_echo),<br> PHP_RINIT(fetion_echo),<br> PHP_RSHUTDOWN(fetion_echo),<br> PHP_MINFO(fetion_echo),<br> #if ZEND_MODULE_API_NO >= 20010901<br> "0.1",<br> #endif<br> STANDARD_MODULE_PROPERTIES<br> };
这里初始化了一个C语言中的结构体,每个PHP Extension其实就是一个zend_module_entry结构体,在该结构体中定义了每个扩展所需的字段,大家可以通过查看 zend_module_entry源代码看到。就本例而言,我们简单的介绍一下上面的代码:
1. STANDARD_MODULE_HEADER:C语言的宏,用来初始化zend_module_entry的前几个字段,包括结构体大小等?
2. fetion_echo:指定了扩展的名字,对应结构体中的name字段?
3. fetion_echo_functions:一个zend_function_entry类型的数组,指向扩展的函数表,所有需要暴露给用户的函数都需要在该函数表中注册?
4. PHP_MINIT(fetion_echo):模块初始化回调函数,在扩展被加载时调用,MINIT = Module Initialization?
5. PHP_MSHUTDOWN(fetion_echo):模块卸载回调函数,在扩展杯卸载时调用,MSHUTDOWN = Module Shutdown?
6. PHP_RINIT(fetion_echo):请求初始化回调函数,每个请求开始时调用,RINIT = Request Initialization?
7. PHP_RSHUTDOWN(fetion_echo):请求结束回调函数,每个请求结束时调用,RSHUTDOWN = Request Shutdown?
8. PHP_MINFO(fetion_echo):扩展信息函数,在phpinfo()函数中会调用,用于显示模块的自定义信息?
9. 0.1:指定了扩展的版本号,对应结构体中的version字段?
10. STANDARD_MODULE_PROPERTIES:C语言的宏,用来初始化zend_module_entry的后几个字段
大家可以看到,在4-8我们指定了4个回调函数,这四个函数可以说我们提供了一种注入机制,让我们能够在这几个关键点进行资源的初始化或者资源回 收。另外,需要说明的一点是,所有的回调函数我们都是通过Zend提供的宏定义的,主要是为了防止在PHP运行时的命名冲突问题,事实上不仅仅是函数,包 括函数返回值、全局变量等我们都会使用这种方式。

五. 编写phpinfo()回调函数?
打开fetion_echo.c文件,在PHP_MINFO_FUNCTION里面编写如下代码:
PHP_MINFO_FUNCTION(fetion_echo) {<br> php_info_print_table_start();<br> php_info_print_table_header(2, "fetion_echo support", "enabled");<br><span style="color: #ff0000;">php_info_print_table_row(2, "author", "TerryLee");<br> php_info_print_table_row(2, "version", "0.1");</span> <br> php_info_print_table_end();<br> /* Remove comments if you have entries in php.ini<br> DISPLAY_INI_ENTRIES();<br> */<br> }
这里主要是phpinfo()函数调用时显示自定义信息,用到了四个函数:
1. php_info_print_table_start():定义phpinfo表格开始?
2. php_info_print_table_header():定义phpinfo表格头,第一个参数指定列数,后面指定与第一个参数数量相等的自定义文字信息?
3. php_info_print_table_row():定义phpinfo表格内容,第一个参数指定列数,后面指定与第一个参数数量相等的自定义文字信息?
4. php_info_print_table_end():定义phpinfo表格结尾
在本例中我们定义了表格头,指定扩展是否可用;另外定义了两行内容,指定扩展的作者和版本。

六. 编写核心代码
接下来是时候编写我们的扩展核心代码了,打开php_fetion_echo.h文件,添加一行声明:
PHP_FUNCTION(say_goodbye);
注意这里不是用"原生"的编写C语言函数的方式,而是通过PHP_FUNCTION宏定义(具体原因前面讲过),say_goodbye是我们开发的扩展模块要暴露给用户的函数名称。

打开fetion_echo.c,在这里实现say_goodbye函数:
PHP_FUNCTION(say_goodbye) {<br> char *arg = NULL;<br> int arg_len, len;<br> char *strg;<br> if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",<br> &arg, &arg_len) == FAILURE) {<br> return;<br> }<br> len = spprintf(&strg, 0, "Goodbye %s\n", arg);<br> RETURN_STRINGL(strg, len, 0);<br> }
里面的具体实现很简单,接收到参数之后,返回"Goodybye 参数"字符串,需要解释的是:
1. 参数接收:这里接收函数的参数需要通过zend_parse_parameter函数解析,第一个参数指定用户传入say_goodbye函数的参数个 数,可以通过宏ZEND_NUM_ARGS()生成,TSRMLS_CC用来确保线程安全;第二个参数是一个字符串,每个字母代表一种类型,其中"s"代 表char*或者int类型,"b"代表布尔类型,"l"代表long类型,完整的类型映射可以看这里;后面几个参数是我们定义的局部变量,用来接收传入的参数值
2. 函数返回值:不能使用C语言原生的return语句,而应该使用Zend API里提供的宏定义,如RETURN_STRINGL返回一个字符串;而RETURN_TRUE返回布尔类型true。

声明扩展函数参数信息(要写在头文件 ),我们的函数原型为say_goodbye(name),声明参数方式:
ZEND_BEGIN_ARG_INFO(arg_say_goodbye, 0)<br> ZEND_ARG_INFO(0, name)<br> ZEND_END_ARG_INFO()
这里都是Zend API提供的宏定义,在后面我会专门介绍扩展函数参数声明。实现完say_goodbye函数之后,我们再注册该函数到函数表 fetion_echo_functions(前面介绍过),第一个参数为函数名,第二个参数为函数参数数组信息,如下代码所示:
const zend_function_entry fetion_echo_functions[] = {<br><span style="color: #ff0000;">PHP_FE(say_goodbye, arg_say_goodbye)<br> {NULL, NULL, NULL}</span> <br> };
注意最后一行{NULL, NULL, NULL}是必须的,只有注册到函数表中的函数才能暴露给用户使用。

七. 配置、编译、安装?
在fetion_echo目录下输入如下命令,具体路径请根据自己安装的PHP路径设置:
/usr/local/php5/bin/phpize
注意如果没有安装过m4和autoconf,请先使用下列命令安装 :
sudo apt-get install m4<br> sudo apt-get install autoconf
运行phpize之后,再用ls命令可以看到在fetion_echo目录生成了很多的文件,包括configure文件:

下面就可以安装该扩展了,使用Linux下面的"标准"三步安装模式:
./configure <br> 或者: ./configure --with-php-config=/usr/local/php/bin/php-config<br> make<br> make install
在安装完成后会提示具体的扩展安装路径,然后就可以把该扩展加入到php.ini配置中,注意extension_dir的设置,重启Web服务器。

/etc/init.d/php-fpm restart

八. 运行?
上面步骤都完成后,运行phpinfo()应该可以看到:

编写一个简单的测试脚本,如下所示:
<?php <br> echo say_goodbye("Foo");<br> ?><span class="Apple-converted-space">?</span>
在浏览器里面查看:

如果您能够看到该界面,说明扩展已经工作正常了。

九. 总结
本文通过一个简单的示例,为大家介绍了如何使用Zend API和C语言在Linux下开发一个PHP Extension。下一篇我们看一下如何开发一个简单的类扩展。

参考资料
1. http://www.php.net/manual/en/internals2.buildsys.configunix.php?
2. http://www.php.net/manual/en/internals2.buildsys.skeleton.php

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
php怎么把负数转为正整数php怎么把负数转为正整数Apr 19, 2022 pm 08:59 PM

php把负数转为正整数的方法:1、使用abs()函数将负数转为正数,使用intval()函数对正数取整,转为正整数,语法“intval(abs($number))”;2、利用“~”位运算符将负数取反加一,语法“~$number + 1”。

php怎么实现几秒后执行一个函数php怎么实现几秒后执行一个函数Apr 24, 2022 pm 01:12 PM

实现方法:1、使用“sleep(延迟秒数)”语句,可延迟执行函数若干秒;2、使用“time_nanosleep(延迟秒数,延迟纳秒数)”语句,可延迟执行函数若干秒和纳秒;3、使用“time_sleep_until(time()+7)”语句。

php怎么除以100保留两位小数php怎么除以100保留两位小数Apr 22, 2022 pm 06:23 PM

php除以100保留两位小数的方法:1、利用“/”运算符进行除法运算,语法“数值 / 100”;2、使用“number_format(除法结果, 2)”或“sprintf("%.2f",除法结果)”语句进行四舍五入的处理值,并保留两位小数。

php怎么根据年月日判断是一年的第几天php怎么根据年月日判断是一年的第几天Apr 22, 2022 pm 05:02 PM

判断方法:1、使用“strtotime("年-月-日")”语句将给定的年月日转换为时间戳格式;2、用“date("z",时间戳)+1”语句计算指定时间戳是一年的第几天。date()返回的天数是从0开始计算的,因此真实天数需要在此基础上加1。

php字符串有没有下标php字符串有没有下标Apr 24, 2022 am 11:49 AM

php字符串有下标。在PHP中,下标不仅可以应用于数组和对象,还可应用于字符串,利用字符串的下标和中括号“[]”可以访问指定索引位置的字符,并对该字符进行读写,语法“字符串名[下标值]”;字符串的下标值(索引值)只能是整数类型,起始值为0。

php怎么替换nbsp空格符php怎么替换nbsp空格符Apr 24, 2022 pm 02:55 PM

方法:1、用“str_replace("&nbsp;","其他字符",$str)”语句,可将nbsp符替换为其他字符;2、用“preg_replace("/(\s|\&nbsp\;||\xc2\xa0)/","其他字符",$str)”语句。

php怎么判断有没有小数点php怎么判断有没有小数点Apr 20, 2022 pm 08:12 PM

php判断有没有小数点的方法:1、使用“strpos(数字字符串,'.')”语法,如果返回小数点在字符串中第一次出现的位置,则有小数点;2、使用“strrpos(数字字符串,'.')”语句,如果返回小数点在字符串中最后一次出现的位置,则有。

php怎么读取字符串后几个字符php怎么读取字符串后几个字符Apr 22, 2022 pm 08:31 PM

在php中,可以使用substr()函数来读取字符串后几个字符,只需要将该函数的第二个参数设置为负值,第三个参数省略即可;语法为“substr(字符串,-n)”,表示读取从字符串结尾处向前数第n个字符开始,直到字符串结尾的全部字符。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
2 周前By尊渡假赌尊渡假赌尊渡假赌
仓库:如何复兴队友
1 个月前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒险:如何获得巨型种子
4 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

SublimeText3 英文版

SublimeText3 英文版

推荐:为Win版本,支持代码提示!

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)