- 相關(guān)推薦
php 5.x 擴展開發(fā)要點
導(dǎo)語:php 5.x 擴展開發(fā)要點,最近因項目需要開發(fā)了一個windows dll形式的php擴展,實現(xiàn)訪問soap webservice。下面就由小編為大家介紹一下php 5.x 擴展開發(fā)要點,歡迎大家閱讀!
開發(fā)環(huán)境是visual studio 2010(VC10)。測試用了 xampp-win32-5.6.28-1-VC11-installer。
為什么不直接用php soap擴展
php確實有一個php_soap的官方擴展,對soap webservice操作進行了封裝。在本案例中,此前博主已經(jīng)用gSOAP對某個web service功能進行了封裝,發(fā)布了兩個DLL訪問ws接口,實現(xiàn)數(shù)據(jù)查詢和加載。php擴展是在gSOAP開發(fā)的DLL基礎(chǔ)上,做進一步的封裝。
除此之外,還可以借助gSOAP封裝的DLL,開發(fā)其他語言的擴展,例如python module。良好的功能劃分可以提高復(fù)用性,減少工作重復(fù)。
安裝XAMPP
安裝的時候,至少選擇安裝apache和php。
基本代碼結(jié)構(gòu)
php以extension的形式提供擴展。位于擴展功能底層核心的是zend引擎。
windows需要包含頭文件
#include "zend_config.w32.h"
/* include standard header */
#include "php.h"
PHP擴展的開發(fā),主要通過一組宏定義,完成擴展的框架構(gòu)建。例如
PHP_MINIT_FUNCTION(CustomExt); // module加載。通常是apache啟動的時候
PHP_MSHUTDOWN_FUNCTION(CustomExt); //module卸載。通常是apache關(guān)閉的時候。
PHP_RINIT_FUNCTION(CustomExt); //一般對應(yīng)一個php腳本啟動的時候。
PHP_RSHUTDOWN_FUNCTION(CustomExt); // 一般對應(yīng)一個php腳本退出的時候。
而PHP擴展中的函數(shù),通過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);
核心數(shù)據(jù)結(jié)構(gòu)
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
};
這個結(jié)構(gòu)引用了擴展需要的所有東西。PHP核心引擎通過這個結(jié)構(gòu)找到擴展,調(diào)用相關(guān)的函數(shù)。
內(nèi)存管理
基本原則是在哪個層次申請的,就在哪個層次釋放。
在PHP層面,不要用malloc()函數(shù),用php提供的emalloc()或者pemalloc()。這種方法申請的內(nèi)存在php擴展代碼中,不必顯式釋放。php框架對這些內(nèi)存進行了統(tǒng)一的管理。PHP核心可以確保托管內(nèi)存不會發(fā)生內(nèi)存泄露而危及平臺的運行穩(wěn)定。
php擴展可以調(diào)用第三方DLL中定義的函數(shù),返回一個新的類實例。那么這個類實例被創(chuàng)建和被析構(gòu)的地方,都應(yīng)該位于第三方DLL,例如不要在php層面用emalloc()為第三方DLL的對象申請內(nèi)存。
如果使用EG(persistent_list)導(dǎo)致空指針訪問違例,博主建議在MINIT函數(shù)中自定義一個hashtable。
資源如何定義和返回
為了封裝c++結(jié)構(gòu),在PHP中使用自己定義的c++類,需要在php擴展中,定義資源resource。每一種資源類型對應(yīng)著一個唯一的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函數(shù)中,對資源進行定義。主要是定義了對應(yīng)的析構(gòu)函數(shù)。例如
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宏,一個結(jié)構(gòu)被返回到PHP腳本。實際是一個指針,其內(nèi)容是完全透明的。
返回的這個資源,PHP腳本在后續(xù)可以使用。
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得到實際的結(jié)構(gòu)實例。
其他事項
解決http 80端口被占用的問題
windows system后臺進程可能占用了本地80端口,到XAMPP控制面板,config,修改httpd.conf,改成 Listen 8080,監(jiān)聽8080端口。
PHP源碼下載
下載對應(yīng)當(dāng)前版本的PHP源碼。例如
php-5.6.28.tar.gz
http://php.net/distributions/php-5.6.28.tar.gz
解壓為 C:xamppphp-5.6.28
下載依賴包
需要下載bison?蓪⑾嚓P(guān)文件拷貝到windows系統(tǒng)目錄。
http://gnuwin32.sourceforge.net/packages/bison.htm
生成需要的頭文件
利用VC命令行環(huán)境,在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可以不做。這里主要是為了生成構(gòu)建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 擴展開發(fā)要點】相關(guān)文章:
怎么在yaf框架增加php擴展框架07-24
linux下用phpize給PHP動態(tài)添加擴展07-25
無需重新編譯php加入ftp擴展的方法09-04
PHP前端開發(fā)中的性能05-25
PHP開發(fā)中注意的事08-17
php開發(fā)工具排行10-15