php语言 百分网手机站

php 5.x 扩展开发要点

时间:2020-09-02 14:59:03 php语言 我要投稿

php 5.x 扩展开发要点

  导语:php 5.x 扩展开发要点,最近因项目需要开发了一个windows dll形式的php扩展,实现访问soap webservice。下面就由小编为大家介绍一下php 5.x 扩展开发要点,欢迎大家阅读!

  开发环境是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:xamppphp-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.0VC>cd /d C:xamppphp-5.6.28

  C:xamppphp-5.6.28>buildconf.bat

  C:xamppphp-5.6.28>set PATH=C:Program Filesisonin;%PATH%

  C:xamppphp-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-

【php 5.x 扩展开发要点】相关文章:

PHP开发安全保护的要点09-17

PHP扩展程序讲解09-30

PHP PDO的扩展内容08-20

php下zmq扩展安装-208-17

PHP常用开发技巧09-19

怎样编写一个独立的PHP扩展09-18

linux下用phpize给PHP动态添加扩展09-10

PHP开发安全的技巧09-12

PHP开发环境的搭建09-10