PHP擴(kuò)展編寫(xiě)點(diǎn)滴 技巧收集
更新時(shí)間:2010年03月09日 21:34:20 作者:
PHP擴(kuò)展好的資源不多,轉(zhuǎn)的這個(gè)朋友應(yīng)該是個(gè)高手。他在實(shí)踐中摸索出來(lái)的這些經(jīng)驗(yàn)和大家分享。
紅色部分是我的注釋。
更多信息參看:
1.常用的通用功能已經(jīng)封裝好了,在如zen_API.h 頭文件中,不用費(fèi)力查看內(nèi)部細(xì)節(jié),浪費(fèi)時(shí)間。(參考:Extending and Embedding PHP 的附錄A)
2.在terminal中運(yùn)行測(cè)試程序,可以看到擴(kuò)展的內(nèi)部錯(cuò)誤輸出,這一點(diǎn)對(duì)于解決內(nèi)存泄漏問(wèn)題尤其重要。(編譯一個(gè)debug 的 lib)
3.開(kāi)發(fā)過(guò)程中修改Makefile中的“CFLAGS = -g -O2”,去掉優(yōu)化選項(xiàng),增加-Wall和-pedantic,便于調(diào)試和顯示編譯警告;
4.某zval*,但其strval非拷貝的,不可用zval_ptr_dtor(zval**),要用efree(void*)。
5.terminal中的$_SERVER['PWD']有值,但是無(wú)法通過(guò)zend_getenv()取得,原因應(yīng)該是該值無(wú)意義或不可靠。
6.調(diào)用“導(dǎo)出函數(shù)”,可利用INTERNAL_FUNCTION_PARAM_PASSTHRU傳參;聲明的非導(dǎo)出函數(shù)可通過(guò)INTERNAL_FUNCTION_PARAM使用“導(dǎo)出函數(shù)”的參數(shù)。
7.注意:RETURN_TYPE用在選擇分之和循環(huán)等處時(shí),最好置于花括號(hào)中,
或者不用分號(hào),因?yàn)椋?define RETURN_BOOL(b) { RETVAL_BOOL(b); return; }。
8.如果函數(shù)的參數(shù)是引用的,且非標(biāo)量,要先析構(gòu),以防內(nèi)存泄露。
9.拋出異常前最好判斷EG(exception)中是否已經(jīng)存在異常,否則會(huì)造成內(nèi)存泄露。
10.當(dāng)Web服務(wù)器API是ISAPI (IIS)的時(shí)候,zend_getenv函數(shù)是不起作用的。
11.向zend_stack_push()傳入數(shù)據(jù)指針,實(shí)際存儲(chǔ)(copy)的是該指針指向的數(shù)據(jù),換句話說(shuō),傳入的應(yīng)該是要存儲(chǔ)的數(shù)據(jù)的指針。
ZEND_API int zend_stack_push(zend_stack *stack, void *element, int size);
ZEND_API int zend_stack_top(zend_stack *stack, void **element);
其中,size == sizeof(*element);
類似地,zend_hash也是如此,比較zend_hash_update和zend_hash_find。
12.使用add_assoc_zval(HashTable*, const char*, zval*)存儲(chǔ)的是zval*,而非zval,因此,
存儲(chǔ)用戶傳入的參數(shù)時(shí)候,要先拷貝一份新的zval,否則會(huì)發(fā)生不可預(yù)料的事情。
13.zval_dtor(zval*)釋放變量及其內(nèi)部的引用內(nèi)存,zval_ptr_dtor(zval**)先檢查refcount
再?zèng)Q定是否調(diào)用zval_dtor(zval*),zval_copy_dtor(zval*)僅執(zhí)行深層的拷貝,即只拷貝
起內(nèi)部引用的內(nèi)存,而不拷貝zval;
14.如使用VC編譯win的動(dòng)態(tài)鏈接庫(kù),而且代碼中調(diào)用了zend函數(shù),如zend_getenv,在zend.h中定義為:
extern "C" {
extern ZEND_API char *(*zend_getenv)(char *name, size_t name_len TSRMLS_DC);
}
需要引入該函數(shù),如要使用ZEND_API,需要事先取消LIBZEND_EXPORTS(包括VC“設(shè)置”中的預(yù)處理定義),或者使用ZEND_DLIMPORT,
ZEND_DLIMPORT char *(*zend_getenv)(char *name, size_t name_len TSRMLS_DC);
下面取自:zend_config.w32.h
#ifdef LIBZEND_EXPORTS
# define ZEND_API __declspec(dllexport)
#else
# define ZEND_API __declspec(dllimport)
#endif
#define ZEND_DLEXPORT __declspec(dllexport)
#define ZEND_DLIMPORT __declspec(dllimport)
executor_globals_id也需要作如下聲明:
ZEND_DLIMPORT int executor_globals_id;
(這個(gè)比較有用,如果你要手工編譯某些擴(kuò)展的時(shí)候,比如我在編譯sqlite3這個(gè)擴(kuò)展的時(shí)候,就遇到這個(gè)問(wèn)題。)
更多信息參看:
1.常用的通用功能已經(jīng)封裝好了,在如zen_API.h 頭文件中,不用費(fèi)力查看內(nèi)部細(xì)節(jié),浪費(fèi)時(shí)間。(參考:Extending and Embedding PHP 的附錄A)
2.在terminal中運(yùn)行測(cè)試程序,可以看到擴(kuò)展的內(nèi)部錯(cuò)誤輸出,這一點(diǎn)對(duì)于解決內(nèi)存泄漏問(wèn)題尤其重要。(編譯一個(gè)debug 的 lib)
3.開(kāi)發(fā)過(guò)程中修改Makefile中的“CFLAGS = -g -O2”,去掉優(yōu)化選項(xiàng),增加-Wall和-pedantic,便于調(diào)試和顯示編譯警告;
4.某zval*,但其strval非拷貝的,不可用zval_ptr_dtor(zval**),要用efree(void*)。
5.terminal中的$_SERVER['PWD']有值,但是無(wú)法通過(guò)zend_getenv()取得,原因應(yīng)該是該值無(wú)意義或不可靠。
6.調(diào)用“導(dǎo)出函數(shù)”,可利用INTERNAL_FUNCTION_PARAM_PASSTHRU傳參;聲明的非導(dǎo)出函數(shù)可通過(guò)INTERNAL_FUNCTION_PARAM使用“導(dǎo)出函數(shù)”的參數(shù)。
7.注意:RETURN_TYPE用在選擇分之和循環(huán)等處時(shí),最好置于花括號(hào)中,
或者不用分號(hào),因?yàn)椋?define RETURN_BOOL(b) { RETVAL_BOOL(b); return; }。
8.如果函數(shù)的參數(shù)是引用的,且非標(biāo)量,要先析構(gòu),以防內(nèi)存泄露。
9.拋出異常前最好判斷EG(exception)中是否已經(jīng)存在異常,否則會(huì)造成內(nèi)存泄露。
10.當(dāng)Web服務(wù)器API是ISAPI (IIS)的時(shí)候,zend_getenv函數(shù)是不起作用的。
11.向zend_stack_push()傳入數(shù)據(jù)指針,實(shí)際存儲(chǔ)(copy)的是該指針指向的數(shù)據(jù),換句話說(shuō),傳入的應(yīng)該是要存儲(chǔ)的數(shù)據(jù)的指針。
ZEND_API int zend_stack_push(zend_stack *stack, void *element, int size);
ZEND_API int zend_stack_top(zend_stack *stack, void **element);
其中,size == sizeof(*element);
類似地,zend_hash也是如此,比較zend_hash_update和zend_hash_find。
12.使用add_assoc_zval(HashTable*, const char*, zval*)存儲(chǔ)的是zval*,而非zval,因此,
存儲(chǔ)用戶傳入的參數(shù)時(shí)候,要先拷貝一份新的zval,否則會(huì)發(fā)生不可預(yù)料的事情。
13.zval_dtor(zval*)釋放變量及其內(nèi)部的引用內(nèi)存,zval_ptr_dtor(zval**)先檢查refcount
再?zèng)Q定是否調(diào)用zval_dtor(zval*),zval_copy_dtor(zval*)僅執(zhí)行深層的拷貝,即只拷貝
起內(nèi)部引用的內(nèi)存,而不拷貝zval;
14.如使用VC編譯win的動(dòng)態(tài)鏈接庫(kù),而且代碼中調(diào)用了zend函數(shù),如zend_getenv,在zend.h中定義為:
extern "C" {
extern ZEND_API char *(*zend_getenv)(char *name, size_t name_len TSRMLS_DC);
}
需要引入該函數(shù),如要使用ZEND_API,需要事先取消LIBZEND_EXPORTS(包括VC“設(shè)置”中的預(yù)處理定義),或者使用ZEND_DLIMPORT,
ZEND_DLIMPORT char *(*zend_getenv)(char *name, size_t name_len TSRMLS_DC);
下面取自:zend_config.w32.h
復(fù)制代碼 代碼如下:
#ifdef LIBZEND_EXPORTS
# define ZEND_API __declspec(dllexport)
#else
# define ZEND_API __declspec(dllimport)
#endif
#define ZEND_DLEXPORT __declspec(dllexport)
#define ZEND_DLIMPORT __declspec(dllimport)
executor_globals_id也需要作如下聲明:
ZEND_DLIMPORT int executor_globals_id;
(這個(gè)比較有用,如果你要手工編譯某些擴(kuò)展的時(shí)候,比如我在編譯sqlite3這個(gè)擴(kuò)展的時(shí)候,就遇到這個(gè)問(wèn)題。)
相關(guān)文章
php創(chuàng)建基本身份認(rèn)證站點(diǎn)的方法詳解
本篇文章是對(duì)php創(chuàng)建基本身份認(rèn)證站點(diǎn)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
php通過(guò)COM類調(diào)用組件的實(shí)現(xiàn)代碼
COM(Component Object Model)組件對(duì)象模型,是一種跨應(yīng)用和語(yǔ)言共享二進(jìn)制代碼的方法。COM可以作為DLL被本機(jī)程序載入也可以通過(guò)DCOM被遠(yuǎn)程進(jìn)程調(diào)用2012-01-01
Ajax+PHP快速上手及簡(jiǎn)單應(yīng)用說(shuō)明
對(duì)于Ajax,最核心的一個(gè)對(duì)象是XMLHttpRequest,所有的Ajax操作都離不開(kāi)對(duì)這個(gè)對(duì)象的操作2013-07-07
php實(shí)現(xiàn)模擬登陸方正教務(wù)系統(tǒng)抓取課表
這篇文章主要介紹了php實(shí)現(xiàn)模擬登陸方正教務(wù)系統(tǒng)抓取課表的相關(guān)資料,需要的朋友可以參考下2015-05-05
PHP代碼加密和擴(kuò)展解密實(shí)戰(zhàn)
這篇文章主要介紹了PHP代碼加密和擴(kuò)展解密實(shí)戰(zhàn),對(duì)加密解密感興趣的同學(xué),可以參考下2021-04-04
php實(shí)現(xiàn)接口api數(shù)據(jù)簽名及驗(yàn)簽
api數(shù)據(jù)簽名作用就是通過(guò)使用簽名可以驗(yàn)證數(shù)據(jù)在傳輸過(guò)程中是否被篡改或修改,下面小編就來(lái)為大家介紹一下php如何實(shí)現(xiàn)接口api數(shù)據(jù)簽名及驗(yàn)簽吧2023-11-11

