ホームページ >php教程 >php手册 >PHP Windows 扩展的开发(1)

PHP Windows 扩展的开发(1)

WBOY
WBOYオリジナル
2016-06-06 20:00:271691ブラウズ

做为从事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。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。