欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  php教程

PHP Windows 扩展的开发(1)

程序员文章站 2022-06-03 13:46:43
...

做为从事PHP开发的人来讲, 有些时候要自己写一些扩展来方便自己的应用。 网络上有很多的PHP开发的例程, 有的讲的还不错, 有的很简单,我把自己学习的过程记录下来。 开发PHP Extension的过程基本可以分为如下几步: 1. 生成扩展框架 2. dsp配置 3. 编写核

做为从事PHP开发的人来讲, 有些时候要自己写一些扩展来方便自己的应用。

网络上有很多的PHP开发的例程, 有的讲的还不错, 有的很简单,我把自己学习的过程记录下来。

开发PHP Extension的过程基本可以分为如下几步:
1. 生成扩展框架
2. dsp配置
3. 编写核心代码
4. 配置、编译
5. 配置php.ini

生成扩展框架

下载PHP源代码,我使用的是PHP 5.2.5。进入PHP源代码目录可以看到有个ext目录,这里是和PHP Extension有关可以看到很多已经存在的PHP Extension,如pdo_mysql,json等

PHP Windows 扩展的开发(1)

linux和windows会使用不同的方法来生成skeleton.

本文主要讲述在windows下的开发, 有两种方法

1. 安装cygwin,然后使用上图中的windows那个文件 php ext_skel_win32.php -extname=, 这个网上有很多 的例子 , 本人不想装cygwin所以采用的下面的方法。

2. 直接修改skeleton文件的内容 。

首先将ext/skeleton拷贝一份, 将名字改为你想用的extname, 本文用hello world为例。

PHP Windows 扩展的开发(1) =>>>>PHP Windows 扩展的开发(1)

dsp 配置

再将php/dev目录下的php5t.lib拷贝到当前的目录下。

将上面4个文件中所有的extname 变成 hello_world, 将EXTNAME 变成HELLO_WORLD, 注意大小写

这样就可以进行简单的编译生成 dsw工程文件。

分析PHP Extension核心代码

为了下面更好的介绍,这里先简单的介绍PHP Extension核心代码,打开hello_world.c文件

这里初始化了一个C语言中的结构体,每个PHP Extension其实就是一个zend_module_entry结构体,在该结构体中定义了每个扩展所需的字段,大家可以通过查看 zend_module_entry源代码看到。就本例而言,我们简单的介绍一下上面的代码:

1. STANDARD_MODULE_HEADER:C语言的宏,用来初始化zend_module_entry的前几个字段,包括结构体大小等
2. hello_world:指定了扩展的名字,对应结构体中的name字段
3. hello_world_functions:一个zend_function_entry类型的数组,指向扩展的函数表,所有需要暴露给用户的函数都需要在该函数表中注册
4. PHP_MINIT(hello_world):模块初始化回调函数,在扩展被加载时调用,MINIT = Module Initialization
5. PHP_MSHUTDOWN(hello_world):模块卸载回调函数,在扩展杯卸载时调用,MSHUTDOWN = Module Shutdown
6. PHP_RINIT(hello_world):请求初始化回调函数,每个请求开始时调用,RINIT = Request Initialization
7. PHP_RSHUTDOWN(hello_world):请求结束回调函数,每个请求结束时调用,RSHUTDOWN = Request Shutdown
8. PHP_MINFO(hello_world):扩展信息函数,在phpinfo()函数中会调用,用于显示模块的自定义信息。
9. 0.1:指定了扩展的版本号,对应结构体中的version字段
10. STANDARD_MODULE_PROPERTIES:C语言的宏,用来初始化zend_module_entry的后几个字段

大家可以看到,在4-8我们指定了4个回调函数,这四个函数可以说我们提供了一种注入机制,让我们能够在这几个关键点进行资源的初始化或者资源回 收。另外,需要说明的一点是,所有的回调函数我们都是通过Zend提供的宏定义的,主要是为了防止在PHP运行时的命名冲突问题,事实上不仅仅是函数,包 括函数返回值、全局变量等我们都会使用这种方式。

编写phpinfo()回调函数

打开hello_world.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_hello_world.h文件,添加一行声明:

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

打开hello_world.c,在这里实现say_hello函数:

里面的具体实现很简单,接收到参数之后,返回“Hello 参数”字符串,需要解释的是:

1. 参数接收:这里接收函数的参数需要通过zend_parse_parameter函数解析,第一个参数指定用户传入say_hello函数的参数个 数,可以通过宏ZEND_NUM_ARGS()生成,TSRMLS_CC用来确保线程安全;第二个参数是一个字符串,每个字母代表一种类型,其中”s”代 表char*或者int类型,“b”代表布尔类型,“l”代表long类型,完整的类型映射可以看这里 ;后面几个参数是我们定义的局部变量,用来接收传入的参数值

2. 函数返回值:不能使用C语言原生的return语句,而应该使用Zend API里提供的宏定义,如RETURN_STRINGL返回一个字符串;而RETURN_TRUE返回布尔类型true。

声明扩展函数参数信息,我们的函数原型为say_hello(name),声明参数方式:

这里都是Zend API提供的宏定义,在后面我会专门介绍扩展函数参数声明。实现完say_hello函数之后,我们再注册该函数到函数表 hello_world_functions(前面介绍过),第一个参数为函数名,第二个参数为函数参数数组信息,如下代码所示:

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

配置、编译、安装

直接用VC6生成php_hello_world.dll, 将其拷贝到php/ext目录下, 配置php.ini如下

PHP Windows 扩展的开发(1)

运行

上面的步骤完成后, 运行 php -i| findstr "hello_world"

PHP Windows 扩展的开发(1)

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

会得到 如下

PHP Windows 扩展的开发(1)

总结

本文通过一个简单的示例,介绍了如何使用Zend API和C语言在windows下开发一个PHP Extension。