现在的位置: 首页 > 综合 > 正文

PHP扩展开发(1):快速入门(转载)

2019年11月12日 ⁄ 综合 ⁄ 共 5958字 ⁄ 字号 评论关闭

转载自:

http://terrylee.me/blog/post/2011/02/12/php-extension-part1.aspx

一. 摘要

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所示:

001

注意在该目录下有一个ext_skel脚本文件,接下来我们将会用它来生成Linux环境下PHP Extension代码框架,而ext_skel_win32.php是windows下的生成脚本。ext_skel完整的命令格式为:

./ext_skel --extname=module [--proto=file] [--stubs=file] [--xml[=file]] 
           [--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所示:

002

在这里有几个比较重要的文件,我们需要介绍一下:

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”开头的都是注释,暂时不用考虑。我们能用到只有下面几行:


其实大家都能看明白,如果扩展使用了一些外部的引用,就使用下面的三行,否则使用最后面的三行,由于我们只是开发一个简单的echo扩展,没有使用任何外部引用,只要取消掉最后三行的注释就行:



保存退出,至此配置文件就完成了。

四. 分析PHP Extension核心代码

为了下面更好的介绍,这里先简单的介绍PHP Extension核心代码,打开fetion_echo.c文件,可以看到如下一段代码:

这里初始化了一个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里面编写如下代码:

这里主要是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文件,添加一行声明:


注意这里不是用“原生”的编写C语言函数的方式,而是通过PHP_FUNCTION宏定义(具体原因前面讲过),say_goodbye是我们开发的扩展模块要暴露给用户的函数名称。

打开fetion_echo.c,在这里实现say_goodbye函数:

里面的具体实现很简单,接收到参数之后,返回“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
API提供的宏定义,在后面我会专门介绍扩展函数参数声明。实现完say_goodbye函数之后,我们再注册该函数到函数表
fetion_echo_functions(前面介绍过),第一个参数为函数名,第二个参数为函数参数数组信息,如下代码所示:


注意最后一行{NULL, NULL, NULL}是必须的,只有注册到函数表中的函数才能暴露给用户使用。

七. 配置、编译、安装

在fetion_echo目录下输入如下命令,具体路径请根据自己安装的PHP路径设置:

/usr/local/php5/bin/phpize

注意如果没有安装过m4和autoconf,请先使用下列命令安装 :

sudo apt-get install m4 
sudo apt-get install autoconf

运行phpize之后,再用ls命令可以看到在fetion_echo目录生成了很多的文件,包括configure文件:

003

下面就可以安装该扩展了,使用Linux下面的“标准”三步安装模式:

./configure 
make 
make install 

在安装完成后会提示具体的扩展安装路径,然后就可以把该扩展加入到php.ini配置中,注意extension_dir的设置,重启Web服务器。

八. 运行

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

005

编写一个简单的测试脚本,如下所示:


在浏览器里面查看:

006

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

九. 总结

本文通过一个简单的示例,为大家介绍了如何使用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

 

 

抱歉!评论已关闭.