摘要:在這些情況下,應(yīng)將相應(yīng)的變量轉(zhuǎn)換為純,使用此變量從到和相應(yīng)的創(chuàng)建宏從,到,。因此使用標(biāo)志的宏被移除,和。宏可以用于在析構(gòu)函數(shù)中達(dá)到實(shí)際的指針值。另外,如果使用添加元素,析構(gòu)函數(shù)也負(fù)責(zé)指針本身的解除分配。應(yīng)使用最佳的宏,而不是舊的和功能。
許多經(jīng)常使用的API函數(shù)已經(jīng)更改,例如HashTable API; 這個(gè)頁面致力于記錄盡可能多的實(shí)際影響擴(kuò)展和核心代碼的更改。 強(qiáng)烈建議在閱讀本指南之前閱讀phpng-int中有關(guān)PHPNG實(shí)現(xiàn)的一般信息。
這不是一個(gè)涵蓋所有可能情況的完整指南。 這是一個(gè)在大多數(shù)情況下有用的匯總。 我希望它對(duì)大多數(shù)用戶級(jí)擴(kuò)展來說是足夠的。 然而,如果你沒有在這里找到一些信息,發(fā)現(xiàn)一個(gè)解決方案,因?yàn)樗赡軐?duì)其他人有用 - 隨時(shí)完善您的方法。
一般建議嘗試使用PHPNG編譯擴(kuò)展。 查看編譯錯(cuò)誤和警告。 他們可以顯示出75%需要修改的地方。
在調(diào)試模式下編譯和測(cè)試擴(kuò)展(使用 -enable-debug 來配置PHP)。它將在運(yùn)行時(shí)使用 assert() 函數(shù)捕獲一些錯(cuò)誤。 您還將看到有關(guān)內(nèi)存泄漏的信息。
zvalPHPNG不需要任何指向指向zval的指針的參與。大多數(shù)zval**變量和參數(shù)必須更改為zval*。 使用這些變量的相應(yīng)Z_*_ PP()宏應(yīng)該更改為Z_*_P()。
在許多地方PHPNG直接使用zval(消除了分配和釋放的需求)。 在這些情況下,應(yīng)將相應(yīng)的zval *變量轉(zhuǎn)換為純zval,使用此變量從Z_*_P()到Z_*()和相應(yīng)的創(chuàng)建宏從ZVAL_*(var,...)到ZVAL_*(&var,...)。 一定要小心傳遞zval和&運(yùn)算的地址。 PHPNG幾乎從 不需要 傳遞 zval * 的地址。 在某些地方應(yīng)該刪除 & 運(yùn)算。
有關(guān)zval分配的宏 ALLOC_ZVAL , ALLOC_INIT_ZVAL 和 MAKE_STD_ZVAL 被移除。 在大多數(shù)情況下,它們的用法表明zval *需要更改為純zval。 宏INIT_PZVAL也被刪除,它的用法在大多數(shù)情況下應(yīng)該被刪除。
- zval *zv; - ALLOC_INIT_ZVAL(); - ZVAL_LONG(zv, 0); + zval zv; + ZVAL_LONG(&zv, 0);
zval結(jié)構(gòu)已完全更改。 現(xiàn)在它的定義是:
struct _zval_struct { zend_value value; /* value */ union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar type, /* active type */ zend_uchar type_flags, zend_uchar const_flags, zend_uchar reserved) /* various IS_VAR flags */ } v; zend_uint type_info; } u1; union { zend_uint var_flags; zend_uint next; /* hash collision chain */ zend_uint str_offset; /* string offset */ zend_uint cache_slot; /* literal cache slot */ } u2; };
zend_value如下:
typedef union _zend_value { long lval; /* long value */ double dval; /* double value */ zend_refcounted *counted; zend_string *str; zend_array *arr; zend_object *obj; zend_resource *res; zend_reference *ref; zend_ast_ref *ast; zval *zv; void *ptr; zend_class_entry *ce; zend_function *func; } zend_value;
主要的區(qū)別是,現(xiàn)在我們處理標(biāo)量和復(fù)雜類型不同。 PHP不在堆中分配標(biāo)量值,而是直接在VM堆棧上,在HashTables和對(duì)象內(nèi)部。 它們 不再 是引用計(jì)數(shù)和垃圾收集的主體。 標(biāo)量值沒有引用計(jì)數(shù)器,不再支持 Z_ADDREF *() , Z_DELREF *() , Z_REFCOUNT *() 和 Z_SET_REFCOUNT *() 宏。 在大多數(shù)情況下,你應(yīng)該判斷zval是否支持這些宏,然后再調(diào)用它們。 否則你會(huì)得到一個(gè)assert()或崩潰。
- Z_ADDREF_P(zv) + if (Z_REFCOUNTED_P(zv)) {Z_ADDREF_P(zv);} # or equivalently + Z_TRY_ADDREF_P(zv);
應(yīng)使用 ZVAL_COPY_VALUE() 宏復(fù)制zval值。
如果需要,可以使用 ZVAL_COPY() 宏復(fù)制和增加引用計(jì)數(shù)器。
可以使用 ZVAL_DUP() 宏來完成 zval(zval_copy_ctor) 的復(fù)制。
如果將zval *轉(zhuǎn)換為zval并且提前使用NULL來指示未定義的值,那么現(xiàn)在可以改用IS_UNDEF類型。 它可以使用 ZVAL_UNDEF(&zv) 設(shè)置并可以使用if(Z_ISUNDEF(zv))進(jìn)行檢查。
如果要使用cast-semantics而不修改原始zval來獲取zval的long/double/string值,現(xiàn)在可以使用 zval_get_long(zv) , zval_get_double(zv) 和zval_get_string(zv) API簡(jiǎn)化代碼:
- zval tmp; - ZVAL_COPY_VALUE(&tmp, zv); - zval_copy_ctor(&tmp); - convert_to_string(&tmp); - // ... - zval_dtor(&tmp); + zend_string *str = zval_get_string(zv); + // ... + zend_string_release(str);
查看 zend_types.h 代碼獲取更多詳細(xì)信息: https://github.com/php/php-sr...
參考PHPNG中的 zval 不再有 is_ref 標(biāo)志。 引用是使用多帶帶的復(fù)數(shù)引用計(jì)數(shù)類型 IS_REFERENCE 實(shí)現(xiàn)的。 仍然可以使用 Z_ISREF *() 宏來檢查給定的 zval 是否被引用。 實(shí)際上,它只是檢查給定的zval的類型是否等于IS_REFERENCE。 因此使用is_ref標(biāo)志的宏被移除:Z_SET_ISREF *(),Z_UNSET_ISREF *() 和 Z_SET_ISREF_TO *() 。 它們的用法應(yīng)該以下列方式改變:
- Z_SET_ISREF_P(zv); + ZVAL_MAKE_REF(zv); - Z_UNSET_ISREF_P(zv); + if (Z_ISREF_P(zv)) {ZVAL_UNREF(zv);}
以前的引用可以直接檢查引用的類型。 現(xiàn)在我們必須通過 Z_REFVAL *() 宏來間接檢查它。
- if (Z_ISREF_P(zv) && Z_TYPE_P(zv) == IS_ARRAY) {} + if (Z_ISREF_P(zv) && Z_TYPE_P(Z_REFVAL_P(zv)) == IS_ARRAY) {}
或使用 ZVAL_DEREF() 宏執(zhí)行手動(dòng)取消引用:
- if (Z_ISREF_P(zv)) {...} - if (Z_TYPE_P(zv) == IS_ARRAY) { + if (Z_ISREF_P(zv)) {...} + ZVAL_DEREF(zv); + if (Z_TYPE_P(zv) == IS_ARRAY) {Booleans
IS_BOOL不再存在,但IS_TRUE和IS_FALSE是依然是它的類型:
- if ((Z_TYPE_PP(item) == IS_BOOL || Z_TYPE_PP(item) == IS_LONG) && Z_LVAL_PP(item)) { + if (Z_TYPE_P(item) == IS_TRUE || (Z_TYPE_P(item) == IS_LONG && Z_LVAL_P(item))) {
將刪除 Z_BVAL *() 宏。 注意, IS_FALSE/IS_TRUE 在 Z_LVAL *() 的返回值里是沒有定義的。
Strings可以使用相同的宏 Z_STRVAL *() 和 Z_STRLEN *() 來訪問字符串的值/長(zhǎng)度。 但是現(xiàn)在字符串表示的下劃線數(shù)據(jù)結(jié)構(gòu)是 zend_string (在多帶帶的部分中描述)。 zend_string可以通過 Z_STR *() 宏從zval中檢索。 它也可以通過 Z_STRHASH *() 獲取字符串的哈希值。
如果代碼需要檢查給定的字符串是否是可轉(zhuǎn)為int,現(xiàn)在應(yīng)該使用zend_string(不是char *):
- if (IS_INTERNED(Z_STRVAL_P(zv))) { + if (IS_INTERNED(Z_STR_P(zv))) {
創(chuàng)建字符串zvals有點(diǎn)改變。 以前的宏,如 ZVAL_STRING() 有一個(gè)額外的參數(shù),告訴是否應(yīng)該復(fù)制給定的字符。 現(xiàn)在這些宏總是必須創(chuàng)建 zend_string 結(jié)構(gòu),所以這個(gè)參數(shù)變得沒用了。 但是,如果它的實(shí)際值為0,則可以釋放原始字符串,以避免內(nèi)存泄漏。
- ZVAL_STRING(zv, str, 1); + ZVAL_STRING(zv, str); - ZVAL_STRINGL(zv, str, len, 1); + ZVAL_STRINGL(zv, str, len); - ZVAL_STRING(zv, str, 0); + ZVAL_STRING(zv, str); + efree(str); - ZVAL_STRINGL(zv, str, len, 0); + ZVAL_STRINGL(zv, str, len); + efree(str);
類似的宏,如 RETURN_STRING() , RETVAL_STRINGS() 等等和一些內(nèi)部API函數(shù)也是如此。
- add_assoc_string(zv, key, str, 1); + add_assoc_string(zv, key, str); - add_assoc_string(zv, key, str, 0); + add_assoc_string(zv, key, str); + efree(str);
可以直接使用 zend_string API并直接從zend_string創(chuàng)建zval來避免雙重新分配。
- char * str = estrdup("Hello"); - RETURN_STRING(str); + zend_string *str = zend_string_init("Hello", sizeof("Hello")-1, 0); + RETURN_STR(str);
Z_STRVAL *() 現(xiàn)在應(yīng)該用作只讀對(duì)象。 它不可能分配任何東西。 它可以修改多帶帶的字符,但在做之前,你必須確保這個(gè)字符串沒有被引用到其他地方(它不是interned,它的reference-counter是1)。 此外,在字符串修改后,可能需要重置計(jì)算的哈希值。
SEPARATE_ZVAL(zv); Z_STRVAL_P(zv)[0] = Z_STRVAL_P(zv)[0] + ("A" - "a"); + zend_string_forget_hash_val((Z_STR_P(zv))zend_string API
Zend有一個(gè)新的 zend_string API,除了zend_string是在zval中的字符串表示的下劃線結(jié)構(gòu),這些結(jié)構(gòu)也被用于以前使用 char * 和 int 的大部分代碼庫。
可以使用 zend_string_init(char * val,size_t len,int persistent) 函數(shù)創(chuàng)建zend_strings(不是IS_STRING zvals)。 實(shí)際字符可以作為 str→val 和字符串長(zhǎng)度作為 str→len 訪問。 字符串的哈希值應(yīng)通過 zend_string_hash_val 函數(shù)訪問。 如果需要,它將重新計(jì)算哈希值。
字符串應(yīng)該使用 zend_string_release() 函數(shù)釋放,這不需要空閑內(nèi)存,因?yàn)橄嗤淖址赡軓膸讉€(gè)地方引用。
如果你打算在某個(gè)地方保持 zend_string 指針,你應(yīng)該增加它的reference-counter或使用 zend_string_copy() 函數(shù),它會(huì)為你做。 在許多地方,代碼復(fù)制字符只是為了保持值(不修改),可以使用這個(gè)函數(shù)。
- ptr->str = estrndup(Z_STRVAL_P(zv), Z_STRLEN_P(zv)); + ptr->str = zend_string_copy(Z_STR_P(zv)); ... - efree(str); + zend_string_release(str);
如果復(fù)制的字符串要更改,您可以使用 zend string_dup() :
- char *str = estrndup(Z_STRVAL_P(zv), Z_STRLEN_P(zv)); + zend_string *str = zend_string_dup(Z_STR_P(zv)); ... - efree(str); + zend_string_release(str);
具有舊宏的代碼也是支持的,因此無需切換到新宏。
在某些情況下,在實(shí)際字符串?dāng)?shù)據(jù)已知之前分配字符串緩沖區(qū)是有意義的。 您可以使用 zend_string_alloc() 和 zend_string_realloc() 函數(shù)來完成。
- char *ret = emalloc(16+1); - md5(something, ret); - RETURN_STRINGL(ret, 16, 0); + zend_string *ret = zend_string_alloc(16, 0); + md5(something, ret->val); + RETURN_STR(ret);
不是所有的擴(kuò)展代碼都必須將 char * 轉(zhuǎn)換為 zend_string 。 由擴(kuò)展維護(hù)者決定哪種類型在每種特定情況下更合適。
查看 zend_string.h 代碼了解更多詳細(xì)信息:https://github.com/php/php-sr...
smart_str 和 smart_string為了一致的命名約定,舊的smart_str API被重命名為smart_string。 它可以像以前一樣使用,除了新的名稱。
- smart_str str = {0}; - smart_str_appendl(str, " ", sizeof(" ") - 1); - smart_str_0(str); - RETURN_STRINGL(implstr.c, implstr.len, 0); + smart_string str = {0}; + smart_string_appendl(str, " ", sizeof(" ") - 1); + smart_string_0(str); + RETVAL_STRINGL(str.c, str.len); + smart_string_free(&str);
此外,引入了一個(gè)新的 zend_str API,它直接與 zend_string 一起工作:
- smart_str str = {0}; - smart_str_appendl(str, " ", sizeof(" ") - 1); - smart_str_0(str); - RETURN_STRINGL(implstr.c, implstr.len, 0); + smart_str str = {0}; + smart_str_appendl(&str, " ", sizeof(" ") - 1); + smart_str_0(&str); + if (str.s) { + RETURN_STR(str.s); + } else { + RETURN_EMPTY_STRING(); + }
smart_str 定義如下:
typedef struct { zend_string *s; size_t a; } smart_str;
smart_str和smart_string的API非常相似,實(shí)際上它們重復(fù)PHP5中使用的API。 所以采用代碼不是一個(gè)大問題。 最大的問題是自動(dòng)為每個(gè)特定情況選擇什么,但它取決于最終結(jié)果的使用方式。
請(qǐng)注意,可能需要更改先前檢查的空 smart_str :
- if (smart_str->c) { + if (smart_str->s) {strprintf
除了 sprintf() 和 vsprintf() 函數(shù),我們引入了類似的函數(shù),產(chǎn)生zend_string ,而不是 char * 。 它取決于您決定何時(shí)應(yīng)該更改為新的變體。
PHPAPI zend_string *vstrpprintf(size_t max_len, const char *format, va_list ap); PHPAPI zend_string *strpprintf(size_t max_len, const char *format, ...);Arrays
數(shù)組實(shí)現(xiàn)或多或少相同,但是,如果以前的下劃線結(jié)構(gòu)被實(shí)現(xiàn)為指向 HashTable 的指針,現(xiàn)在我們?cè)谶@里有一個(gè)指向 zend_array 的內(nèi)部保持 HashTable 。 HashTable 可以像之前一樣使用 Z_ARRVAL *() 宏讀取,但現(xiàn)在不可能將指針更改為HashTable。 它只能通過宏Z_ARR *()獲取或設(shè)置指向整個(gè)zend_array的指針。
創(chuàng)建數(shù)組的最好方法是使用舊的 array_init() 函數(shù),但也可以使用 ZVAL_NEW_ARR() 創(chuàng)建新的未初始化數(shù)組,或者通過 ZVAL_ARR() 使用 zend_array 結(jié)構(gòu)初始化數(shù)組。
一些數(shù)組可能是不可變的(可以使用 Z_IMMUTABLE() 宏來檢查)。 如果代碼需要修改它們,它們必須首先復(fù)制。 使用內(nèi)部位置指針通過不可變數(shù)組迭代也是不可能的。 可以使用帶有外部位置指針的舊迭代API或使用在多帶帶部分中描述的新的HashTable迭代API來遍歷這些數(shù)組。
HashTable APIHashTable API 明顯的改變,它可能會(huì)導(dǎo)致擴(kuò)展兼容中的一些麻煩。
首先,現(xiàn)在HashTables總是使用zval。 即使我們存儲(chǔ)一個(gè)任意指針,它被打包到zval與特殊類型IS_PTR。 無論如何,這簡(jiǎn)化了zval的工作:
- zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key)+1, (void*)&zv, sizeof(zval**), NULL) == SUCCESS) { + if (zend_hash_update(EG(function_table), Z_STR_P(key), zv)) != NULL) {
大多數(shù)API函數(shù)直接返回請(qǐng)求的值(而不是通過引用參數(shù)使用附加參數(shù)并返回SUCCESS / FAILURE):
- if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key)+1, (void**)&zv_ptr) == SUCCESS) { + if ((zv = zend_hash_find(ht, Z_STR_P(key))) != NULL) {
鍵表示為zend_string。 大多數(shù)函數(shù)有兩種形式。 一個(gè)以zend_string作為鍵,另一個(gè)以char *作為鍵,長(zhǎng)度對(duì)。
重要說明:當(dāng)鍵值字符串的長(zhǎng)度不包括尾隨零(0)。 在某些地方,必須刪除或添加+1 / -1:
- if (zend_hash_find(ht, "value", sizeof("value"), (void**)&zv_ptr) == SUCCESS) { + if ((zv = zend_hash_str_find(ht, "value", sizeof("value")-1)) != NULL) {
這也適用于zend_hash之外的其他hashtable相關(guān)的API。 例如:
- add_assoc_bool_ex(&zv, "valid", sizeof("valid"), 0); + add_assoc_bool_ex(&zv, "valid", sizeof("valid") - 1, 0);
API提供了一組多帶帶的函數(shù)來處理任意指針。 這些函數(shù)與 _ptr 后綴具有相同的名稱。
- if (zend_hash_find(EG(class_table), Z_STRVAL_P(key), Z_STRLEN_P(key)+1, (void**)&ce_ptr) == SUCCESS) { + if ((ce_ptr = zend_hash_find_ptr(EG(class_table), Z_STR_P(key))) != NULL) { - zend_hash_update(EG(class_table), Z_STRVAL_P(key), Z_STRLEN_P(key)+1, (void*)&ce, sizeof(zend_class_entry*), NULL) == SUCCESS) { + if (zend_hash_update_ptr(EG(class_table), Z_STR_P(key), ce)) != NULL) {
API提供了一組多帶帶的函數(shù)來存儲(chǔ)任意大小的內(nèi)存塊。 這些函數(shù)與 _mem 后綴具有相同的名稱,并且它們實(shí)現(xiàn)為相應(yīng) _ptr 函數(shù)的內(nèi)聯(lián)封裝。 這不意味著如果使用_mem或_ptr變量存儲(chǔ)某些內(nèi)容。 它總是可以使用 zend_hash_find_ptr() 找回來。
- zend_hash_update(EG(function_table), Z_STRVAL_P(key), Z_STRLEN_P(key)+1, (void*)func, sizeof(zend_function), NULL) == SUCCESS) { + if (zend_hash_update_mem(EG(function_table), Z_STR_P(key), func, sizeof(zend_function))) != NULL) {
增加了新的元素插入的新的優(yōu)化功能。 它們旨在用于代碼僅添加新元素(不能與現(xiàn)有鍵重疊)的情況。 例如,當(dāng)您將一個(gè)HashTable的一些元素復(fù)制到一個(gè)新的。 所有這些函數(shù)都有 _new 后綴。
zval* zend_hash_add_new(HashTable *ht, zend_string *key, zval *zv); zval* zend_hash_str_add_new(HashTable *ht, char *key, int len, zval *zv); zval* zend_hash_index_add_new(HashTable *ht, pzval *zv); zval* zend_hash_next_index_insert_new(HashTable *ht, pzval *zv); void* zend_hash_add_new_ptr(HashTable *ht, zend_string *key, void *pData); ...
HashTable析構(gòu)函數(shù)現(xiàn)在總是接收zval *(即使我們使用zend_hash_add_ptr或zend_hash_add_mem來添加元素)。 Z_PTR_P() 宏可以用于在析構(gòu)函數(shù)中達(dá)到實(shí)際的指針值。 另外,如果使用 zend_hash_add_mem 添加元素,析構(gòu)函數(shù)也負(fù)責(zé)指針本身的解除分配。
- void my_ht_destructor(void *ptr) + void my_ht_destructor(zval *zv) { - my_ht_el_t *p = (my_ht_el_t*) ptr; + my_ht_el_t *p = (my_ht_el_t*) Z_PTR_P(zv); ... + efree(p); // this efree() is not always necessary } );
所有 zend_hash_apply_*() 函數(shù)的回調(diào),以及 zend_hash_copy() 和 zend_hash_merge() 的回調(diào)應(yīng)該改變?yōu)榻邮?zval * 而不是 void * && ,與析構(gòu)函數(shù)相同。 這些函數(shù)中的一些還接收指向 zend_hash_key 結(jié)構(gòu)的指針。 它的定義以下面的方式改變。 對(duì)于字符串鍵,h包含hash函數(shù)的值,key是實(shí)際的字符串。 對(duì)于整數(shù)鍵,h包含數(shù)字鍵值,鍵為 NULL 。
typedef struct _zend_hash_key { ulong h; zend_string *key; } zend_hash_key;
在某些情況下,將 zend_hash_apply_*() 函數(shù)的用法更改為使用新的HashTable迭代API是有意義的。 這可能導(dǎo)致更小和更有效的代碼。
可參考zend_hash.h :https://github.com/php/php-sr...
HashTable Iteration API我們提供幾個(gè)專門的宏來遍歷HashTables的元素(和鍵)。 宏的第一個(gè)參數(shù)是哈希表,其他是在每個(gè)迭代步驟上分配的變量。
ZEND_HASH_FOREACH_VAL(ht, val) ZEND_HASH_FOREACH_KEY(ht, h, key) ZEND_HASH_FOREACH_PTR(ht, ptr) ZEND_HASH_FOREACH_NUM_KEY(ht, h) ZEND_HASH_FOREACH_STR_KEY(ht, key) ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, val) ZEND_HASH_FOREACH_KEY_VAL(ht, h, key, val)
應(yīng)使用最佳的宏,而不是舊的reset, current, 和move功能。
- HashPosition pos; ulong num_key; - char *key; - uint key_len; + zend_string *key; - zval **pzv; + zval *zv; - - zend_hash_internal_pointer_reset_ex(&ht, &pos); - while (zend_hash_get_current_data_ex(&ht, (void**)&ppzval, &pos) == SUCCESS) { - if (zend_hash_get_current_key_ex(&ht, &key, &key_len, &num_key, 0, &pos) == HASH_KEY_IS_STRING){ - } + ZEND_HASH_FOREACH_KEY_VAL(ht, num_key, key, val) { + if (key) { //HASH_KEY_IS_STRING + } ........ - zend_hash_move_forward_ex(&ht, &pos); - } + } ZEND_HASH_FOREACH_END();Objects
TODO: …
Custom ObjectsTODO: …
zend_object struct定義為:
struct _zend_object { zend_refcounted gc; zend_uint handle; // TODO: may be removed ??? zend_class_entry *ce; const zend_object_handlers *handlers; HashTable *properties; HashTable *guards; /* protects from __get/__set ... recursion */ zval properties_table[1]; };
我們內(nèi)聯(lián)了properties_table以獲得更好的訪問性能,但這也帶來了一個(gè)問題,我們習(xí)慣于這樣定義一個(gè)自定義對(duì)象:
struct custom_object { zend_object std; void *custom_data; } zend_object_value custom_object_new(zend_class_entry *ce TSRMLS_DC) { zend_object_value retval; struct custom_object *intern; intern = emalloc(sizeof(struct custom_object)); zend_object_std_init(&intern->std, ce TSRMLS_CC); object_properties_init(&intern->std, ce); retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) custom_free_storage, NULL TSRMLC_CC); intern->handle = retval.handle; retval.handlers = &custom_object_handlers; return retval; } struct custom_object* obj = (struct custom_object *)zend_objects_get_address(getThis());
但現(xiàn)在,zend_object是變量長(zhǎng)度現(xiàn)在(內(nèi)聯(lián)的properties_table)。 因此上述代碼應(yīng)改為:
struct custom_object { void *custom_data; zend_object std; } zend_object * custom_object_new(zend_class_entry *ce TSRMLS_DC) { # Allocate sizeof(custom) + sizeof(properties table requirements) struct custom_object *intern = ecalloc(1, sizeof(struct custom_object) + zend_object_properties_size(ce)); # Allocating: # struct custom_object { # void *custom_data; # zend_object std; # } # zval[ce->default_properties_count-1] zend_object_std_init(&intern->std, ce TSRMLS_CC); ... custom_object_handlers.offset = XtOffsetOf(struct custom_obj, std); custom_object_handlers.free_obj = custom_free_storage; intern->std.handlers = custom_object_handlers; return &intern->std; } # Fetching the custom object: static inline struct custom_object * php_custom_object_fetch_object(zend_object *obj) { return (struct custom_object *)((char *)obj - XtOffsetOf(struct custom_object, std)); } #define Z_CUSTOM_OBJ_P(zv) php_custom_object_fetch_object(Z_OBJ_P(zv)); struct custom_object* obj = Z_CUSTOM_OBJ_P(getThis());zend_object_handlers
一個(gè)新的項(xiàng)目偏移被添加到zend_object_handlers,你應(yīng)該總是將它定義為在你的自定義對(duì)象結(jié)構(gòu)中的zend_object偏移量。
它用 zend_objects_store_* 來查找分配的內(nèi)存的正確起始地址。
// An example in spl_array memcpy(&spl_handler_ArrayObject, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); spl_handler_ArrayObject.offset = XtOffsetOf(spl_array_object, std);
對(duì)象的內(nèi)存現(xiàn)在將由 zend_objects_store_* 釋放,因此您不應(yīng)釋放自定義對(duì)象free_obj處理程序中的內(nèi)存。
Resources類型 IS_RESOURCE 的zvals不再保留資源句柄。 無法使用 Z_LVAL_*() 檢索資源句柄。 相反,應(yīng)該使用 Z_RES_*() 宏直接檢索資源記錄。 資源記錄由 zend_resource 結(jié)構(gòu)表示。 它包含:
tyep - 資源類型,
ptr - 指向?qū)嶋H數(shù)據(jù)的指針,
handle - 數(shù)字資源索引(用于兼容性)以及引用計(jì)數(shù)器的服務(wù)字段。
實(shí)際上,這個(gè)zend_resurce結(jié)構(gòu)是間接引用的zend_rsrc_list_entry的替代。 所有出現(xiàn)的zend_rsrc_list_entry應(yīng)替換為zend_resource。
zend_list_find() 函數(shù)被刪除,因?yàn)橘Y源被直接訪問。
- long handle = Z_LVAL_P(zv); - int type; - void *ptr = zend_list_find(handle, &type); + long handle = Z_RES_P(zv)->handle; + int type = Z_RES_P(zv)->type; + void *ptr = = Z_RES_P(zv)->ptr;
刪除 Z_RESVAL_*() 宏可以改用 Z_RES*():
- long handle = Z_RESVAL_P(zv); + long handle = Z_RES_P(zv)->handle;
ZEND_REGISTER_RESOURCE / ZEND_FETCH_RESOURCE()被刪除
- ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, &link_arg, link_id, LE_LINK, le_link, le_plink); //if you are sure that link_arg is a IS_RESOURCE type, then use : +if ((ib_link = (ibase_db_link *)zend_fetch_resource2(Z_RES_P(link_arg), LE_LINK, le_link, le_plink)) == NULL) { + RETURN_FALSE; +} //otherwise, if you know nothing about link_arg"s type, use +if ((ib_link = (ibase_db_link *)zend_fetch_resource2_ex(link_arg, LE_LINK, le_link, le_plink)) == NULL) { + RETURN_FALSE; +} - REGISTER_RESOURCE(return_value, result, le_result); + RETURN_RES(zend_register_resource(result, le_result);
zend_list_addref()和zend_list_delref()函數(shù)被刪除。 資源使用與所有zval相同的引用計(jì)數(shù)機(jī)制。
- zend_list_addref(Z_LVAL_P(zv)); + Z_ADDREF_P(zv);
同樣的:
- zend_list_addref(Z_LVAL_P(zv)); + Z_RES_P(zv)->gc.refcount++;
zend_list_delete()將指針指向zend_resource結(jié)構(gòu),而不是資源句柄:
- zend_list_delete(Z_LVAL_P(zv)); + zend_list_delete(Z_RES_P(zv));
在大多數(shù)用戶擴(kuò)展函數(shù)(如mysql_close())中,應(yīng)該使用zend_list_close()而不是zend_list_delete()。 這將關(guān)閉實(shí)際連接并釋放擴(kuò)展特定的數(shù)據(jù)結(jié)構(gòu),但不釋放zend_reference結(jié)構(gòu)。 可能仍然從zval(s)引用。 這也不會(huì)遞減資源引用計(jì)數(shù)器。
- zend_list_delete(Z_LVAL_P(zv)); + zend_list_close(Z_RES_P(zv));Parameters Parsing API changes
"l"說明符現(xiàn)在期望一個(gè)zend_long參數(shù),而不是一個(gè)long參數(shù)。
- long lval; + zend_long lval; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &lval) == FAILURE) {
"s"說明符的長(zhǎng)度參數(shù)現(xiàn)在需要一個(gè)size_t變量,而不是一個(gè)int變量。
char *str; - int len; + size_t len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len) == FAILURE) {
除了需要字符串的"s"說明符,PHPNG引入了"S"說明符,它也期望字符串,但將參數(shù)放在zend_string變量中。 在某些情況下,直接使用zend_string是首選。 (例如,當(dāng)接收到的字符串用作HashTable API中的鍵時(shí)。
- char *str; - int len; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len) == FAILURE) { + zend_string *str; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "S", &str) == FAILURE) {
PHPNG不再使用zval **,所以它不再需要"Z"說明符了。 它必須替換為"z"。
- zval **pzv; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &pzv) == FAILURE) { + zval *zv; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zv) == FAILURE) {
"+"和"*"說明符現(xiàn)在只返回zval數(shù)組(而不是之前的zval **數(shù)組)
- zval ***argv = NULL; + zval *argv = NULL; int argn; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &argv, &argn) == FAILURE) {
通過引用傳遞的參數(shù)應(yīng)該分配到引用的值。 有可能分離這樣的參數(shù),得到引用值在第一位。
- zval **ret; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &ret) == FAILURE) { + zval *ret; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &ret) == FAILURE) { return; } - ZVAL_LONG(*ret, 0); + ZVAL_LONG(ret, 0);Call Frame Changes (zend_execute_data)
關(guān)于記錄在zend_execute_data結(jié)構(gòu)鏈中的每個(gè)函數(shù)調(diào)用的信息。 EG(current_execute_data) 指向當(dāng)前執(zhí)行函數(shù)的調(diào)用幀(以前的zend_execute_data結(jié)構(gòu)僅為用戶級(jí)PHP函數(shù)創(chuàng)建)。 我將嘗試逐個(gè)字段解釋舊的和新的調(diào)用框架結(jié)構(gòu)之間的區(qū)別。
zend_execute_data.opline - 當(dāng)前執(zhí)行的用戶函數(shù)的指令指針。 對(duì)于內(nèi)部函數(shù),其值未定義。 (以前為內(nèi)部函數(shù),其值為NULL)
zend_execute_data.function_state - 此字段已刪除。 應(yīng)該使用zend_execute_data.call。
zend_execute_data.call - 以前它是一個(gè)指向當(dāng)前call_slot的指針。 目前它是一個(gè)指向當(dāng)前調(diào)用函數(shù)的zend_execute_data的指針。 此字段最初為NULL,然后由ZEND_INIT_FCALL(或類似)操作碼更改,然后由ZEND_FO_FCALL恢復(fù)。 語法嵌套函數(shù)調(diào)用,像foo($ a,bar($ c)),通過zend_execute_data.prev_nested_call構(gòu)造一個(gè)這樣的結(jié)構(gòu)鏈
zend_execute_data.op_array - 此字段由zend_execute_data.func替換,因?yàn)楝F(xiàn)在它可能不僅表示用戶函數(shù),而且表示內(nèi)部函數(shù)。
zend_execute_data.func - 當(dāng)前執(zhí)行的函數(shù)
zend_execute_data.object - $ this當(dāng)前執(zhí)行的函數(shù)(以前它是一個(gè)zval ,現(xiàn)在它是一個(gè)zend_object )
zend_execute_data.symbol_table - 當(dāng)前符號(hào)表或NULL
zend_execute_data.prev_execute_data - 回溯調(diào)用鏈的鏈接
original_return_value,current_scope,current_called_scope,current_this - 這些字段保留舊值以在調(diào)用后恢復(fù)它們。 現(xiàn)在他們被刪除。
zend_execute_data.scope - 當(dāng)前執(zhí)行函數(shù)的作用域(這是一個(gè)新字段)。
zend_execute_data.called_scope - called_scope當(dāng)前執(zhí)行的函數(shù)(這是一個(gè)新字段)。
zend_execute_data.run_time_cache - 當(dāng)前執(zhí)行函數(shù)的運(yùn)行時(shí)緩存。 這是一個(gè)新字段,實(shí)際上它是op_array.run_time_cache的副本。
zend_execute_data.num_args - 傳遞給函數(shù)的參數(shù)數(shù)量(這是一個(gè)新字段)
zend_execute_data.return_value - 指向zval *的指針,其中當(dāng)前執(zhí)行的op_array應(yīng)存儲(chǔ)結(jié)果。 如果調(diào)用不關(guān)心返回值,它可以為NULL。 (這是一個(gè)新字段)。
參數(shù)存儲(chǔ)在zval槽中的函數(shù)直接在zend_execute_data結(jié)構(gòu)之后。 它們可以使用 ZEND_CALL_ARG(execute_data,arg_num) 宏訪問。 對(duì)于用戶PHP函數(shù),第一個(gè)參數(shù)與第一個(gè)編譯的變量 - CV0等重疊。如果調(diào)用者傳遞了被調(diào)用者接收的更多參數(shù),所有額外的參數(shù)都被復(fù)制到被調(diào)用者CV和TMP變量之后。
Executor Globals - EG() ChangesEG(symbol_table) - 被改為一個(gè)zend_array(以前它是一個(gè)HashTable)。 到達(dá)下劃線HashTable不是一個(gè)大問題
- symbols = zend_hash_num_elements(&EG(symbol_table)); + symbols = zend_hash_num_elements(&EG(symbol_table).ht);
刪除EG(uninitialized_zval_ptr)和EG(error_zval_ptr)。 使用&EG(uninitialized_zval)和&EG(error_zval)。
EG(current_execute_data) - 這個(gè)字段的含義改變了一點(diǎn)。 以前它是一個(gè)指向最后執(zhí)行的PHP函數(shù)的框架的指針。 現(xiàn)在它是一個(gè)指向最后執(zhí)行的調(diào)用框架(如果它的用戶或內(nèi)部函數(shù),不介意)。 可以獲得最后一個(gè)op_array遍歷調(diào)用鏈列表的zend_execute_data結(jié)構(gòu)。
zend_execute_data *ex = EG(current_execute_data); + while (ex && (!ex->func || !ZEND_USER_CODE(ex->func->type))) { + ex = ex->prev_execute_data; + } if (ex) {
EG(opline_ptr) - 。 請(qǐng)改用execute_data→opline。
EG(return_value_ptr_ptr) - 已刪除。 請(qǐng)改用execute_data→return_value。
EG(active_symbol_table) - 被刪除。 請(qǐng)使用execute_data→symbol_table。
EG(active_op_array) - 被刪除。 請(qǐng)使用execute_data→func。
EG(called_scope) - 被刪除。 請(qǐng)改用execute_data→called_scope。
EG(This) - 變成了zval,以前它是一個(gè)指向zval的指針。 用戶代碼不應(yīng)該修改它。
EG(in_execution))。 如果EG(current_excute_data)`不為NULL,我們正在執(zhí)行某事。
EG(異常)和EG(prev_exception) - 被轉(zhuǎn)換為指向zend_object的指針,以前它們是指向zval的指針。
Opcodes changesZEND_DO_FCALL_BY_NAME - 已刪除, ZEND_INIT_FCALL_BY_NAME已添加。
ZEND_BIND_GLOBAL - 被添加到處理“全局$ var”
ZEND_STRLEN - 已添加以替換strlen函數(shù)
ZEND_TYPE_CHECK - 已添加以替換is_array / is_int / is_ *(如果可能)
ZEND_DEFINED - 被添加來替換zif_defined如果可能(如果只有一個(gè)參數(shù),它的常量字符串,它不在命名空間樣式)
ZEND_SEND_VAR_EX - 是為了做比 ZEND_SEND_VAR更多的檢查,如果條件無法在編譯時(shí)間內(nèi)解決
ZEND_SEND_VAL_EX - 已添加,以進(jìn)行比 ZEND_SEND_VAL更多的檢查,如果條件無法在編譯時(shí)間內(nèi)解決
ZEND_INIT_USER_CALL - 被添加以替換call_user_func(_array)如果可能的話,如果在編譯時(shí)無法找到該函數(shù),否則它可以轉(zhuǎn)換為 ZEND_INIT_FCALL
ZEND_SEND_ARRAY - 被添加發(fā)送第二個(gè)參數(shù),call_user_func_array的數(shù)組在被轉(zhuǎn)換為操作碼
ZEND_SEND_USER - 被添加以發(fā)送call_user_func的參數(shù),在它被轉(zhuǎn)換為操作碼之后
temp_variable PCRE一些pcre API使用或返回zend_string現(xiàn)在。 F.e. php_pcre_replace返回一個(gè)zend_string,并將zend_string作為第一個(gè)參數(shù)。 仔細(xì)檢查他們的聲明以及編譯器警告,這很可能是錯(cuò)誤的參數(shù)類型。
phpng-upgrading.txt · Last modified: 2016/01/21 17:18 by nikic
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/22149.html
摘要:本次發(fā)布標(biāo)志著新的重要的系列的開始。經(jīng)過社區(qū)投票,新項(xiàng)目命名為。結(jié)果如下結(jié)果如下四新特性標(biāo)量類型聲明有兩種模式強(qiáng)制默認(rèn)和嚴(yán)格模式。已廢棄的和函數(shù)已被移除。在中,如果發(fā)生這種情況,會(huì)引發(fā)錯(cuò)誤,并且返回。 最好的語言發(fā)布了新的版本,一個(gè)劃時(shí)代的大版本:PHP7。 PHP7修復(fù)了大量BUG,新增了功能和語法糖。這些改動(dòng)涉及到了核心包、GD庫、PDO、ZIP、ZLIB等熟悉和不熟悉的核心功能與...
摘要:安裝源碼在下載并解壓。為不與沖突,文件夾都用,安裝過程中報(bào)錯(cuò)的安裝響應(yīng)的依賴。啟動(dòng)中途如遇到日志文件路徑不存在就手動(dòng)創(chuàng)建并給予寫的權(quán)限。遇到這個(gè)錯(cuò)誤時(shí),要添加個(gè)組再重新啟動(dòng)。的配置這是訪問文件是變成下載文件,因?yàn)椴⑽磁渲庙憫?yīng)處理。 起步 之前在服務(wù)器搭建了lamp環(huán)境,想換用性能更強(qiáng)的nginx作為服務(wù)器軟件,又想將php5升級(jí)為php7.安裝nginx無需贅述:sudo apt-ge...
摘要:截止到目前為止,官方已經(jīng)發(fā)布了的版本,距離發(fā)布第一個(gè)正式版本不會(huì)很遠(yuǎn)了現(xiàn)在來說的重大特性肯定已經(jīng)是定型了,不會(huì)再有什么變動(dòng)了。 截止到目前為止,PHP官方已經(jīng)發(fā)布了php7的RC7版本,距離發(fā)布第一個(gè)正式版本不會(huì)很遠(yuǎn)了!現(xiàn)在來說php7的重大特性肯定已經(jīng)是定型了,不會(huì)再有什么變動(dòng)了。后續(xù)一些版本的迭代主要也就是修修bug,優(yōu)化之類的。下面就來說話我們一直期待的php7會(huì)有那些主要的變化...
摘要:也可以接入項(xiàng)目打包測(cè)試流程做代碼檢測(cè)。擴(kuò)展替換以后廢棄了和擴(kuò)展,項(xiàng)目中使用的使用的類使用的是已經(jīng)廢棄的擴(kuò)展使用擴(kuò)展做兼容替換。測(cè)試方案和大部分公司差不多,項(xiàng)目組劃分了線下開發(fā)環(huán)境預(yù)發(fā)布環(huán)境和生產(chǎn)環(huán)境三個(gè)環(huán)境。 項(xiàng)目由PHP5.5切換至PHP7.1.15 背景 從2015年鳥哥的技術(shù)分享,我們知道PHP7是對(duì)底層實(shí)現(xiàn)得一次完全重構(gòu),函數(shù)調(diào)用機(jī)制和內(nèi)存管理等很多方便做了優(yōu)化,使PHP性能有...
摘要:所以,分配內(nèi)存的宏都被刪掉了。為的輪詢?cè)O(shè)計(jì)了一組宏,使用起來非常方便。 我在公司的生產(chǎn)環(huán)境已經(jīng)升級(jí)了PHP7,大部分活躍的擴(kuò)展都可以兼容PHP7或者有了PHP7的分支,但是處理protocolbuffers數(shù)據(jù)的擴(kuò)展一直沒有人來升級(jí),我只能摸著石頭過河,自己做一把升級(jí)了。目前已經(jīng)編譯通過,處在處理單測(cè)失敗的case階段,歡迎大家一起討論。對(duì)PHP擴(kuò)展升級(jí)可以先看一下官方的升級(jí)說明,ht...
閱讀 3553·2021-11-25 09:43
閱讀 3135·2021-10-08 10:04
閱讀 1625·2019-08-26 12:20
閱讀 2053·2019-08-26 12:09
閱讀 595·2019-08-23 18:25
閱讀 3573·2019-08-23 17:54
閱讀 2322·2019-08-23 17:50
閱讀 803·2019-08-23 14:33