日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

PHP扩展开发指南

發(fā)布時(shí)間:2025/5/22 160 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PHP扩展开发指南 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.1?????使用數(shù)組

曾講到,PHP數(shù)組本質(zhì)上就是個(gè)HashTable,因此訪問數(shù)組就是對(duì)HashTable進(jìn)行操作,Zend為我們提供的一組數(shù)組函數(shù)也只是對(duì)HashTable操作進(jìn)行了簡(jiǎn)單包裝而已。

來看創(chuàng)建數(shù)組,由于數(shù)組也是存在于zval里的,因此要先用MAKE_STD_ZVAL()宏創(chuàng)建一個(gè)zval,之后調(diào)用如下宏將其轉(zhuǎn)化為一個(gè)空數(shù)組:

array_init(zval*)

接下來是朝數(shù)組中添加元素,這對(duì)關(guān)聯(lián)數(shù)組元素和非關(guān)聯(lián)數(shù)組元素要采用不同操作。

?

1.1.1?關(guān)聯(lián)數(shù)組元素

關(guān)聯(lián)數(shù)組采用char*作為key,zval*作為value,可以使用如下宏將已有的zval加入數(shù)組或者更新已有元素:

int add_assoc_zval(zval *arr, char *key, zval *value)

需要特別注意的是,Zend不會(huì)復(fù)制zval,只會(huì)簡(jiǎn)單的儲(chǔ)存其指針,并且不關(guān)心任何引用計(jì)數(shù),因此不能將其他變量的zval或者是棧上的zval傳給它,只能用MAKE_STD_ZVAL()宏構(gòu)建。

Zend為常用的類型定義了相應(yīng)的API,以簡(jiǎn)化我們的操作:

add_assoc_long(zval *array, char *key, long n);
add_assoc_bool(zval *array, char *key, int b);
add_assoc_resource(zval *array, char *key, int r);
add_assoc_double(zval *array, char *key, double d);
add_assoc_string(zval *array, char *key, char *str, int duplicate);
add_assoc_stringl(zval *array, char *key, char *str, uint length, int duplicate);
add_assoc_null(zval *array, char *key);

當(dāng)函數(shù)發(fā)現(xiàn)目標(biāo)元素已經(jīng)存在時(shí),會(huì)首先遞減其原zval的refcount,然后才插入新zval,這就保證了原zval引用信息的正確性。這種行為是通過HashTable.pDestructor(參見1.2.1)實(shí)現(xiàn)的,每次刪除一個(gè)元素時(shí),HashTable都將對(duì)被刪元素調(diào)用這個(gè)函數(shù)指針,而數(shù)組為其HashTable設(shè)置的函數(shù)指針就是用來處理被刪除zval的引用信息。

另外,查看這些函數(shù)的源代碼可以發(fā)現(xiàn)一個(gè)有意思的現(xiàn)象,它們沒有直接使用HashTable操作,而是使用變量符號(hào)表操作,可見關(guān)聯(lián)數(shù)組和變量符號(hào)表就是一種東西。

Zend沒有提供刪除和獲取數(shù)組元素的函數(shù),此類操作只能使用HashTable函數(shù)或者是2.6節(jié)的變量符號(hào)表操作。

1.1.2非關(guān)聯(lián)數(shù)組元素

非關(guān)聯(lián)數(shù)組沒有key,使用index作為hash,相應(yīng)函數(shù)和上面關(guān)聯(lián)數(shù)組的十分類似:

add_index_zval(zval *array, uint idx, zval *value);
add_index_long(zval *array, uint idx, long n);
add_index_bool(zval *array, uint idx, int b);
add_index_resource(zval *array, uint idx, int r);
add_index_double(zval *array, uint idx, double d);
add_index_string(zval *array, uint idx, char *str, int duplicate);
add_index_stringl(zval *array, uint idx, char *str, uint length, int duplicate);
add_index_null(zval *array, uint idx);

如果只是想插入值,而不指定index的話,可以使用如下函數(shù):

add_next_index_zval(zval *array, zval *value);
add_next_index_long(zval *array, long n);
add_next_index_bool(zval *array, int b);
add_next_index_resource(zval *array, int r);
add_next_index_double(zval *array, double d);
add_next_index_string(zval *array, char *str, int duplicate);
add_next_index_stringl(zval *array, char *str, uint length, int duplicate);
add_next_index_null(zval *array);

1.2??????使用資源

1.2.1? 注冊(cè)資源類型

1.1.1節(jié)曾經(jīng)提到,所謂資源就是內(nèi)部數(shù)據(jù)的handle(但是這句話并不全對(duì)),使用資源是比較簡(jiǎn)單的,首先是注冊(cè)一個(gè)資源類型:

int zend_register_list_destructors_ex( rsrc_dtor_func_t ld, rsrc_dtor_func_t pld, char *type_name, int module_number);

第一個(gè)參數(shù)是函數(shù)指針,當(dāng)資源不再被使用或者模塊將被卸載時(shí),Zend使用它來銷毀資源,稍候再作介紹;第二個(gè)參數(shù)和第一個(gè)類似,只是它被用來銷毀持久性資源(*);type_name是資源名稱,用戶可以使用var_dump函數(shù)來讀取;module_number是模塊號(hào),在啟動(dòng)函數(shù)中可以獲取該值。

注冊(cè)過程其實(shí)就是將我們傳入的參數(shù)放到一個(gè)內(nèi)部數(shù)據(jù)結(jié)構(gòu),然后把這個(gè)數(shù)據(jù)結(jié)構(gòu)放入一個(gè)沒有使用key的HashTable里,該函數(shù)返回的值,也就是所謂“資源類型id”,其實(shí)就是HashTable的index。

1.2.1? 注冊(cè)資源

注冊(cè)完資源類型后,就可以注冊(cè)一個(gè)該類型的資源了:

1ZEND_REGISTER_RESOURCE(
2rsrc_result,
3rsrc_pointer,
4rsrc_type)

src_pointer是個(gè)指針類型,就是你的資源的handle, 通常是指向內(nèi)部數(shù)據(jù)的指針,當(dāng)然也可以是index或者其它標(biāo)志符;rsrc_type是上面獲取的資源類型id;rsrc_result是個(gè)已有的zval,注冊(cè)完成后,資源的id就被放入該zval,同時(shí)其type也被設(shè)為IS_RESOURCE,通常是傳入return_value,以將資源返回給用戶。

在內(nèi)部,Zend使用如下數(shù)據(jù)結(jié)構(gòu)表示一個(gè)資源:

1typedef struct _zend_rsrc_list_entry {
2????void *ptr;
3????int type;
4????int refcount;
5} zend_rsrc_list_entry;

ptr和type就是我們?cè)谏厦鎮(zhèn)魅氲膮?shù);refcount是引用計(jì)數(shù),由Zend維護(hù),當(dāng)引用減到0時(shí),Zend會(huì)銷毀該資源。不出所料的是,這個(gè)數(shù)據(jù)結(jié)構(gòu)也被組織在一個(gè)HashTable里,并且沒有使用key,僅僅使用index——這就是zval里存放的東西。現(xiàn)在資源的整個(gè)脈絡(luò)已經(jīng)清晰:通過zval可以獲得資源id,通過資源id可以獲得資源handle和資源類型id,通過資源類型id可以獲得資源的銷毀函數(shù)。 現(xiàn)在講一下銷毀函數(shù):

1typedef void (*rsrc_dtor_func_t)(
2zend_rsrc_list_entry *rsrc
3TSRMLS_DC);

rsrc是需要被銷毀的資源,我們?cè)诤瘮?shù)的實(shí)現(xiàn)中可以通過它獲得資源的handle,并且加以處理,比如釋放內(nèi)存塊、關(guān)閉數(shù)據(jù)庫連接或是關(guān)閉文件描述符等。

1.2.3 ?獲取資源

當(dāng)創(chuàng)建了資源后,用戶通常都要調(diào)用創(chuàng)建者提供的函數(shù)來操作資源,此時(shí)我們需要從用戶傳入的zval中取出資源:

1ZEND_FETCH_RESOURCE(
2rsrc,? rsrc_type,
3passed_id, default_id,
4resource_type_name, resource_type)

首個(gè)參數(shù)用于接收handle值,第二個(gè)參數(shù)是handle值的類型,這個(gè)函數(shù)會(huì)擴(kuò)展成“rsrc = (rsrc_type) zend_fetch_resource(…)”,因此應(yīng)該保證rsrc是rsrc_type類型的;passed_id是用戶傳入的zval,這里使用zval**類型,函數(shù)從中取得資源id;default_id用來直接指定資源id,如果該值不是-1,則使用它,并且忽略passed_id,所以通常應(yīng)該使用-1;resource_type_name是資源名稱,當(dāng)獲取資源失敗時(shí),函數(shù)使用它來輸出錯(cuò)誤信息;resource_type是資源類型,如果取得的資源不是該類型的,則函數(shù)返回NULL,這用于防止用戶傳入一個(gè)其他類型資源的zval。

不過,這個(gè)宏確實(shí)比較難用,用其底層的宏反倒更加容易些:

1zend_list_find(id, type)

id是要查找的資源id;type是int*類型,用于接收取出的資源的類型,可以用它來判斷這是不是我們想要的資源;函數(shù)最后返回資源的handle,失敗返回NULL。

1.2.4? 維護(hù)引用計(jì)數(shù)

通常,當(dāng)用戶對(duì)資源類型的PHP變量執(zhí)行賦值或是unset之類操作時(shí),Zend會(huì)自動(dòng)維護(hù)資源的引用計(jì)數(shù)。但有時(shí),我們也需要手動(dòng)進(jìn)行,比如我們要復(fù)用一個(gè)數(shù)據(jù)庫連接或者用戶調(diào)用我們提供的close操作關(guān)閉一個(gè)文件,此時(shí)可以使用如下宏:

1zend_list_addref(id)
2zend_list_delete(id)

id是資源id,這兩個(gè)宏分別增加和減少目標(biāo)資源的引用計(jì)數(shù),第二個(gè)宏還會(huì)在引用計(jì)數(shù)減到0時(shí),調(diào)用先前注冊(cè)的函數(shù)銷毀資源。

轉(zhuǎn)載于:https://www.cnblogs.com/lsl8966/archive/2012/12/10/2811944.html

《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的PHP扩展开发指南的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。