频道栏目
首页 > 程序开发 > Web开发 > php > 正文
php 5.x 扩展开发要点
2017-07-25 09:30:05      个评论    来源:wanghuiict的博客  
收藏   我要投稿

php 5.x 扩展开发要点,最近因项目需要开发了一个windows dll形式的php扩展,实现访问soap webservice。现在简单记录一下要点,以备查看。

开发环境是visual studio 2010(VC10)。测试用了 xampp-win32-5.6.28-1-VC11-installer。

为什么不直接用php soap扩展

php确实有一个php_soap的官方扩展,对soap webservice操作进行了封装。在本案例中,此前博主已经用gSOAP对某个web service功能进行了封装,发布了两个DLL访问ws接口,实现数据查询和加载。php扩展是在gSOAP开发的DLL基础上,做进一步的封装。

除此之外,还可以借助gSOAP封装的DLL,开发其他语言的扩展,例如python module。良好的功能划分可以提高复用性,减少工作重复。

安装XAMPP

安装的时候,至少选择安装apache和php。

基本代码结构

php以extension的形式提供扩展。位于扩展功能底层核心的是zend引擎。

windows需要包含头文件

#include "zend_config.w32.h"

/* include standard header */

#include "php.h"

PHP扩展的开发,主要通过一组宏定义,完成扩展的框架构建。例如

PHP_MINIT_FUNCTION(CustomExt); // module加载。通常是apache启动的时候

PHP_MSHUTDOWN_FUNCTION(CustomExt); //module卸载。通常是apache关闭的时候。

PHP_RINIT_FUNCTION(CustomExt); //一般对应一个php脚本启动的时候。

PHP_RSHUTDOWN_FUNCTION(CustomExt); // 一般对应一个php脚本退出的时候。

而PHP扩展中的函数,通过PHP_FUNCTION定义。例如

PHP_FUNCTION(paradb_wsquery_new);

PHP_FUNCTION(paradb_wsquery_prepare);

PHP_FUNCTION(paradb_wsquery_query);

PHP_FUNCTION(paradb_anytype_print);

PHP_FUNCTION(paradb_wsload_new);

PHP_FUNCTION(paradb_wsload_prepare);

PHP_FUNCTION(paradb_wsload_load);

核心数据结构

zend_module_entry CustomExtModule_module_entry = {

STANDARD_MODULE_HEADER,

"CustomExt Module",

CustomExtModule_functions,

PHP_MINIT(CustomExt),

PHP_MSHUTDOWN(CustomExt),

PHP_RINIT(CustomExt),

PHP_RSHUTDOWN(CustomExt),

NULL,

NO_VERSION_YET, STANDARD_MODULE_PROPERTIES

};

这个结构引用了扩展需要的所有东西。PHP核心引擎通过这个结构找到扩展,调用相关的函数。

内存管理

基本原则是在哪个层次申请的,就在哪个层次释放。

在PHP层面,不要用malloc()函数,用php提供的emalloc()或者pemalloc()。这种方法申请的内存在php扩展代码中,不必显式释放。php框架对这些内存进行了统一的管理。PHP核心可以确保托管内存不会发生内存泄露而危及平台的运行稳定。

php扩展可以调用第三方DLL中定义的函数,返回一个新的类实例。那么这个类实例被创建和被析构的地方,都应该位于第三方DLL,例如不要在php层面用emalloc()为第三方DLL的对象申请内存。

如果使用EG(persistent_list)导致空指针访问违例,博主建议在MINIT函数中自定义一个hashtable。

资源如何定义和返回

为了封装c++结构,在PHP中使用自己定义的c++类,需要在php扩展中,定义资源resource。每一种资源类型对应着一个唯一的int。例如

int le_paradb_wsquery, le_paradb_xsdany;

#define PHP_PARADB_WSQUERY_RES_NAME "paradb wsquery"

#define PHP_GSOAP_XSD_ANYTYPE_RES_NAME "gsoap xsdany"

#define PHP_PARADB_WSLOAD_RES_NAME "paradb wsload"

在MINIT函数中,对资源进行定义。主要是定义了对应的析构函数。例如

le_paradb_wsquery = zend_register_list_destructors_ex(php_paradb_wsquery_dtor, NULL, PHP_PARADB_WSQUERY_RES_NAME, module_number);

PHP_FUNCTION(paradb_wsquery_new)

{

WsQuery *q;

char *name;

int name_len;

zval* p;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {

RETURN_FALSE;

}

if (name_len < 1) {

php_error_docref(NULL TSRMLS_CC, E_WARNING, "No endpoint given, WsQuery resource not created.");

RETURN_FALSE;

}

paradbc_wsquery_init2(&q, name);

php_printf("[paradb_wsquery_new %p]

", q);

ZEND_REGISTER_RESOURCE(return_value, q, le_paradb_wsquery);

}

通过ZEND_REGISTER_RESOURCE宏,一个结构被返回到PHP脚本。实际是一个指针,其内容是完全透明的。

返回的这个资源,PHP脚本在后续可以使用。

PHP_FUNCTION(paradb_wsquery_query2)

{

WsQuery *q;

zval *zq;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &zq) == FAILURE) {

RETURN_FALSE;

}

ZEND_FETCH_RESOURCE(q, WsQuery*, &zq, -1, PHP_PARADB_WSQUERY_RES_NAME, le_paradb_wsquery);

......

}

通过ZEND_FETCH_RESOURCE宏,PHP扩展代码得到这个resource,从zval得到实际的结构实例。

其他事项

解决http 80端口被占用的问题

windows system后台进程可能占用了本地80端口,到XAMPP控制面板,config,修改httpd.conf,改成 Listen 8080,监听8080端口。

PHP源码下载

下载对应当前版本的PHP源码。例如

php-5.6.28.tar.gz

http://php.net/distributions/php-5.6.28.tar.gz

解压为 C:\xampp\php-5.6.28

下载依赖包

需要下载bison。可将相关文件拷贝到windows系统目录。

http://gnuwin32.sourceforge.net/packages/bison.htm

生成需要的头文件

利用VC命令行环境,在PHP源码目录做一次configure操作。

Setting environment for using Microsoft Visual Studio 2010 x86 tools.

C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC>cd /d C:\xampp\php-5.6.28

C:\xampp\php-5.6.28>buildconf.bat

C:\xampp\php-5.6.28>set PATH=C:\Program Files\bison\bin;%PATH%

C:\xampp\php-5.6.28>configure.bat

nmake可以不做。这里主要是为了生成构建PHP扩展所需的头文件。

注意:建议使用与xampp完全相同的VC版本,否则需要修改config.w32.h中的PHP_COMPILER_ID与xampp的完全一致。例如apache error.log报告错误

PHP Warning: PHP Startup: CustomExt Module: Unable to initialize module

Module compiled with build ID=API20131226,TS,VC10

PHP compiled with build ID=API20131226,TS,VC11

These options need to match

解决办法是手动修改 main/config.w32.h

#define PHP_COMPILER_ID "VC11"

-END-

点击复制链接 与好友分享!回本站首页
上一篇:1.5反射--php反射学习
下一篇:PHP判断手机设备访问
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训

版权所有: 红黑联盟--致力于做实用的IT技术学习网站