国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

[譯]將PHP擴展從PHP5升級到NG(PHP7)

Chaz / 3427人閱讀

摘要:在這些情況下,應將相應的變量轉換為純,使用此變量從到和相應的創建宏從,到,。因此使用標志的宏被移除,和。宏可以用于在析構函數中達到實際的指針值。另外,如果使用添加元素,析構函數也負責指針本身的解除分配。應使用最佳的宏,而不是舊的和功能。

許多經常使用的API函數已經更改,例如HashTable API; 這個頁面致力于記錄盡可能多的實際影響擴展和核心代碼的更改。 強烈建議在閱讀本指南之前閱讀phpng-int中有關PHPNG實現的一般信息。

這不是一個涵蓋所有可能情況的完整指南。 這是一個在大多數情況下有用的匯總。 我希望它對大多數用戶級擴展來說是足夠的。 然而,如果你沒有在這里找到一些信息,發現一個解決方案,因為它可能對其他人有用 - 隨時完善您的方法。

一般建議

嘗試使用PHPNG編譯擴展。 查看編譯錯誤和警告。 他們可以顯示出75%需要修改的地方。

在調試模式下編譯和測試擴展(使用 -enable-debug 來配置PHP)。它將在運行時使用 assert() 函數捕獲一些錯誤。 您還將看到有關內存泄漏的信息。

zval

PHPNG不需要任何指向指向zval的指針的參與。大多數zval**變量和參數必須更改為zval*。 使用這些變量的相應Z_*_ PP()宏應該更改為Z_*_P()

在許多地方PHPNG直接使用zval(消除了分配和釋放的需求)。 在這些情況下,應將相應的zval *變量轉換為純zval,使用此變量從Z_*_P()Z_*()和相應的創建宏從ZVAL_*(var,...)ZVAL_*(&var,...)。 一定要小心傳遞zval和&運算的地址。 PHPNG幾乎從 不需要 傳遞 zval * 的地址。 在某些地方應該刪除 & 運算。

有關zval分配的宏 ALLOC_ZVALALLOC_INIT_ZVALMAKE_STD_ZVAL 被移除。 在大多數情況下,它們的用法表明zval *需要更改為純zval。 宏INIT_PZVAL也被刪除,它的用法在大多數情況下應該被刪除。

-  zval *zv;
-  ALLOC_INIT_ZVAL();
-  ZVAL_LONG(zv, 0);
+  zval zv;
+  ZVAL_LONG(&zv, 0);

zval結構已完全更改。 現在它的定義是:

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;

主要的區別是,現在我們處理標量和復雜類型不同。 PHP不在堆中分配標量值,而是直接在VM堆棧上,在HashTables和對象內部。 它們 不再 是引用計數和垃圾收集的主體。 標量值沒有引用計數器,不再支持 Z_ADDREF *()Z_DELREF *()Z_REFCOUNT *()Z_SET_REFCOUNT *() 宏。 在大多數情況下,你應該判斷zval是否支持這些宏,然后再調用它們。 否則你會得到一個assert()或崩潰。

- Z_ADDREF_P(zv)
+ if (Z_REFCOUNTED_P(zv)) {Z_ADDREF_P(zv);}
# or equivalently
+ Z_TRY_ADDREF_P(zv);

應使用 ZVAL_COPY_VALUE() 宏復制zval值。

如果需要,可以使用 ZVAL_COPY() 宏復制和增加引用計數器。

可以使用 ZVAL_DUP() 宏來完成 zval(zval_copy_ctor) 的復制。

如果將zval *轉換為zval并且提前使用NULL來指示未定義的值,那么現在可以改用IS_UNDEF類型。 它可以使用 ZVAL_UNDEF(&zv) 設置并可以使用if(Z_ISUNDEF(zv))進行檢查。

如果要使用cast-semantics而不修改原始zval來獲取zval的long/double/string值,現在可以使用 zval_get_long(zv)zval_get_double(zv)zval_get_string(zv) API簡化代碼:

- 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 代碼獲取更多詳細信息: https://github.com/php/php-sr...

參考

PHPNG中的 zval 不再有 is_ref 標志。 引用是使用多帶帶的復數引用計數類型 IS_REFERENCE 實現的。 仍然可以使用 Z_ISREF *() 宏來檢查給定的 zval 是否被引用。 實際上,它只是檢查給定的zval的類型是否等于IS_REFERENCE。 因此使用is_ref標志的宏被移除:Z_SET_ISREF *()Z_UNSET_ISREF *()Z_SET_ISREF_TO *() 。 它們的用法應該以下列方式改變:

- Z_SET_ISREF_P(zv);
+ ZVAL_MAKE_REF(zv);

- Z_UNSET_ISREF_P(zv);
+ if (Z_ISREF_P(zv)) {ZVAL_UNREF(zv);}

以前的引用可以直接檢查引用的類型。 現在我們必須通過 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() 宏執行手動取消引用:

- 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_TRUEIS_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_TRUEZ_LVAL *() 的返回值里是沒有定義的。

Strings

可以使用相同的宏 Z_STRVAL *()Z_STRLEN *() 來訪問字符串的值/長度。 但是現在字符串表示的下劃線數據結構是 zend_string (在多帶帶的部分中描述)。 zend_string可以通過 Z_STR *() 宏從zval中檢索。 它也可以通過 Z_STRHASH *() 獲取字符串的哈希值。

如果代碼需要檢查給定的字符串是否是可轉為int,現在應該使用zend_string(不是char *):

- if (IS_INTERNED(Z_STRVAL_P(zv))) {
+ if (IS_INTERNED(Z_STR_P(zv))) {

創建字符串zvals有點改變。 以前的宏,如 ZVAL_STRING() 有一個額外的參數,告訴是否應該復制給定的字符。 現在這些宏總是必須創建 zend_string 結構,所以這個參數變得沒用了。 但是,如果它的實際值為0,則可以釋放原始字符串,以避免內存泄漏。

- 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() 等等和一些內部API函數也是如此。

- 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創建zval來避免雙重新分配。

- char * str = estrdup("Hello");
- RETURN_STRING(str);
+ zend_string *str = zend_string_init("Hello", sizeof("Hello")-1, 0);
+ RETURN_STR(str);

Z_STRVAL *() 現在應該用作只讀對象。 它不可能分配任何東西。 它可以修改多帶帶的字符,但在做之前,你必須確保這個字符串沒有被引用到其他地方(它不是interned,它的reference-counter是1)。 此外,在字符串修改后,可能需要重置計算的哈希值。

  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有一個新的 zend_string API,除了zend_string是在zval中的字符串表示的下劃線結構,這些結構也被用于以前使用 char *int 的大部分代碼庫。

可以使用 zend_string_init(char * val,size_t len,int persistent) 函數創建zend_strings(不是IS_STRING zvals)。 實際字符可以作為 str→val 和字符串長度作為 str→len 訪問。 字符串的哈希值應通過 zend_string_hash_val 函數訪問。 如果需要,它將重新計算哈希值。

字符串應該使用 zend_string_release() 函數釋放,這不需要空閑內存,因為相同的字符串可能從幾個地方引用。

如果你打算在某個地方保持 zend_string 指針,你應該增加它的reference-counter或使用 zend_string_copy() 函數,它會為你做。 在許多地方,代碼復制字符只是為了保持值(不修改),可以使用這個函數。

- 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);

如果復制的字符串要更改,您可以使用 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);

具有舊宏的代碼也是支持的,因此無需切換到新宏。

在某些情況下,在實際字符串數據已知之前分配字符串緩沖區是有意義的。 您可以使用 zend_string_alloc()zend_string_realloc() 函數來完成。

- 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);

不是所有的擴展代碼都必須將 char * 轉換為 zend_string 。 由擴展維護者決定哪種類型在每種特定情況下更合適。

查看 zend_string.h 代碼了解更多詳細信息: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);

此外,引入了一個新的 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_strsmart_string的API非常相似,實際上它們重復PHP5中使用的API。 所以采用代碼不是一個大問題。 最大的問題是自動為每個特定情況選擇什么,但它取決于最終結果的使用方式。

請注意,可能需要更改先前檢查的空 smart_str

- if (smart_str->c) {
+ if (smart_str->s) {
strprintf

除了 sprintf()vsprintf() 函數,我們引入了類似的函數,產生zend_string ,而不是 char * 。 它取決于您決定何時應該更改為新的變體。

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

數組實現或多或少相同,但是,如果以前的下劃線結構被實現為指向 HashTable 的指針,現在我們在這里有一個指向 zend_array 的內部保持 HashTableHashTable 可以像之前一樣使用 Z_ARRVAL *() 宏讀取,但現在不可能將指針更改為HashTable。 它只能通過宏Z_ARR *()獲取或設置指向整個zend_array的指針。

創建數組的最好方法是使用舊的 array_init() 函數,但也可以使用 ZVAL_NEW_ARR() 創建新的未初始化數組,或者通過 ZVAL_ARR() 使用 zend_array 結構初始化數組。

一些數組可能是不可變的(可以使用 Z_IMMUTABLE() 宏來檢查)。 如果代碼需要修改它們,它們必須首先復制。 使用內部位置指針通過不可變數組迭代也是不可能的。 可以使用帶有外部位置指針的舊迭代API或使用在多帶帶部分中描述的新的HashTable迭代API來遍歷這些數組。

HashTable API

HashTable API 明顯的改變,它可能會導致擴展兼容中的一些麻煩。

首先,現在HashTables總是使用zval。 即使我們存儲一個任意指針,它被打包到zval與特殊類型IS_PTR。 無論如何,這簡化了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) {

大多數API函數直接返回請求的值(而不是通過引用參數使用附加參數并返回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。 大多數函數有兩種形式。 一個以zend_string作為鍵,另一個以char *作為鍵,長度對。

重要說明:當鍵值字符串的長度不包括尾隨零(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相關的API。 例如:

- add_assoc_bool_ex(&zv, "valid", sizeof("valid"), 0);
+ add_assoc_bool_ex(&zv, "valid", sizeof("valid") - 1, 0);

API提供了一組多帶帶的函數來處理任意指針。 這些函數與 _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提供了一組多帶帶的函數來存儲任意大小的內存塊。 這些函數與 _mem 后綴具有相同的名稱,并且它們實現為相應 _ptr 函數的內聯封裝。 這不意味著如果使用_mem或_ptr變量存儲某些內容。 它總是可以使用 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) {

增加了新的元素插入的新的優化功能。 它們旨在用于代碼僅添加新元素(不能與現有鍵重疊)的情況。 例如,當您將一個HashTable的一些元素復制到一個新的。 所有這些函數都有 _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析構函數現在總是接收zval *(即使我們使用zend_hash_add_ptr或zend_hash_add_mem來添加元素)。 Z_PTR_P() 宏可以用于在析構函數中達到實際的指針值。 另外,如果使用 zend_hash_add_mem 添加元素,析構函數也負責指針本身的解除分配。

- 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_*() 函數的回調,以及 zend_hash_copy()zend_hash_merge() 的回調應該改變為接收 zval * 而不是 void * && ,與析構函數相同。 這些函數中的一些還接收指向 zend_hash_key 結構的指針。 它的定義以下面的方式改變。 對于字符串鍵,h包含hash函數的值,key是實際的字符串。 對于整數鍵,h包含數字鍵值,鍵為 NULL

typedef struct _zend_hash_key {
    ulong        h;
    zend_string *key;
} zend_hash_key;

在某些情況下,將 zend_hash_apply_*() 函數的用法更改為使用新的HashTable迭代API是有意義的。 這可能導致更小和更有效的代碼。

可參考zend_hash.h :https://github.com/php/php-sr...

HashTable Iteration API

我們提供幾個專門的宏來遍歷HashTables的元素(和鍵)。 宏的第一個參數是哈希表,其他是在每個迭代步驟上分配的變量。

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)

應使用最佳的宏,而不是舊的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 Objects

TODO: …

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];
};

我們內聯了properties_table以獲得更好的訪問性能,但這也帶來了一個問題,我們習慣于這樣定義一個自定義對象:

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());

但現在,zend_object是變量長度現在(內聯的properties_table)。 因此上述代碼應改為:

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

一個新的項目偏移被添加到zend_object_handlers,你應該總是將它定義為在你的自定義對象結構中的zend_object偏移量。

它用 zend_objects_store_* 來查找分配的內存的正確起始地址。

// 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);

對象的內存現在將由 zend_objects_store_* 釋放,因此您不應釋放自定義對象free_obj處理程序中的內存。

Resources

類型 IS_RESOURCE 的zvals不再保留資源句柄。 無法使用 Z_LVAL_*() 檢索資源句柄。 相反,應該使用 Z_RES_*() 宏直接檢索資源記錄。 資源記錄由 zend_resource 結構表示。 它包含:

tyep - 資源類型,

ptr - 指向實際數據的指針,

handle - 數字資源索引(用于兼容性)以及引用計數器的服務字段。

實際上,這個zend_resurce結構是間接引用的zend_rsrc_list_entry的替代。 所有出現的zend_rsrc_list_entry應替換為zend_resource

zend_list_find() 函數被刪除,因為資源被直接訪問。

- 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()函數被刪除。 資源使用與所有zval相同的引用計數機制。

- 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結構,而不是資源句柄:

- zend_list_delete(Z_LVAL_P(zv));
+ zend_list_delete(Z_RES_P(zv));

在大多數用戶擴展函數(如mysql_close())中,應該使用zend_list_close()而不是zend_list_delete()。 這將關閉實際連接并釋放擴展特定的數據結構,但不釋放zend_reference結構。 可能仍然從zval(s)引用。 這也不會遞減資源引用計數器。

- zend_list_delete(Z_LVAL_P(zv));
+ zend_list_close(Z_RES_P(zv));
Parameters Parsing API changes

"l"說明符現在期望一個zend_long參數,而不是一個long參數。

- long lval;
+ zend_long lval;
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &lval) == FAILURE) {

"s"說明符的長度參數現在需要一個size_t變量,而不是一個int變量。

  char *str;
- int len;
+ size_t len;
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len) == FAILURE) {

除了需要字符串的"s"說明符,PHPNG引入了"S"說明符,它也期望字符串,但將參數放在zend_string變量中。 在某些情況下,直接使用zend_string是首選。 (例如,當接收到的字符串用作HashTable API中的鍵時。

- 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) {

"+""*"說明符現在只返回zval數組(而不是之前的zval **數組)

- zval ***argv = NULL;
+ zval *argv = NULL;
  int argn;
  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &argv, &argn) == FAILURE) {

通過引用傳遞的參數應該分配到引用的值。 有可能分離這樣的參數,得到引用值在第一位。

- 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)

關于記錄在zend_execute_data結構鏈中的每個函數調用的信息。 EG(current_execute_data) 指向當前執行函數的調用幀(以前的zend_execute_data結構僅為用戶級PHP函數創建)。 我將嘗試逐個字段解釋舊的和新的調用框架結構之間的區別。

zend_execute_data.opline - 當前執行的用戶函數的指令指針。 對于內部函數,其值未定義。 (以前為內部函數,其值為NULL)

zend_execute_data.function_state - 此字段已刪除。 應該使用zend_execute_data.call。

zend_execute_data.call - 以前它是一個指向當前call_slot的指針。 目前它是一個指向當前調用函數的zend_execute_data的指針。 此字段最初為NULL,然后由ZEND_INIT_FCALL(或類似)操作碼更改,然后由ZEND_FO_FCALL恢復。 語法嵌套函數調用,像foo($ a,bar($ c)),通過zend_execute_data.prev_nested_call構造一個這樣的結構鏈

zend_execute_data.op_array - 此字段由zend_execute_data.func替換,因為現在它可能不僅表示用戶函數,而且表示內部函數。

zend_execute_data.func - 當前執行的函數

zend_execute_data.object - $ this當前執行的函數(以前它是一個zval ,現在它是一個zend_object

zend_execute_data.symbol_table - 當前符號表或NULL

zend_execute_data.prev_execute_data - 回溯調用鏈的鏈接

original_return_valuecurrent_scopecurrent_called_scopecurrent_this - 這些字段保留舊值以在調用后恢復它們。 現在他們被刪除。

zend_execute_data.scope - 當前執行函數的作用域(這是一個新字段)。

zend_execute_data.called_scope - called_scope當前執行的函數(這是一個新字段)。

zend_execute_data.run_time_cache - 當前執行函數的運行時緩存。 這是一個新字段,實際上它是op_array.run_time_cache的副本。

zend_execute_data.num_args - 傳遞給函數的參數數量(這是一個新字段)

zend_execute_data.return_value - 指向zval *的指針,其中當前執行的op_array應存儲結果。 如果調用不關心返回值,它可以為NULL。 (這是一個新字段)。

參數存儲在zval槽中的函數直接在zend_execute_data結構之后。 它們可以使用 ZEND_CALL_ARG(execute_data,arg_num) 宏訪問。 對于用戶PHP函數,第一個參數與第一個編譯的變量 - CV0等重疊。如果調用者傳遞了被調用者接收的更多參數,所有額外的參數都被復制到被調用者CV和TMP變量之后。

Executor Globals - EG() Changes

EG(symbol_table) - 被改為一個zend_array(以前它是一個HashTable)。 到達下劃線HashTable不是一個大問題

- 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) - 這個字段的含義改變了一點。 以前它是一個指向最后執行的PHP函數的框架的指針。 現在它是一個指向最后執行的調用框架(如果它的用戶或內部函數,不介意)。 可以獲得最后一個op_array遍歷調用鏈列表的zend_execute_data結構。

  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) - 。 請改用execute_data→opline

EG(return_value_ptr_ptr) - 已刪除。 請改用execute_data→return_value

EG(active_symbol_table) - 被刪除。 請使用execute_data→symbol_table

EG(active_op_array) - 被刪除。 請使用execute_data→func

EG(called_scope) - 被刪除。 請改用execute_data→called_scope

EG(This) - 變成了zval,以前它是一個指向zval的指針。 用戶代碼不應該修改它。

EG(in_execution))。 如果EG(current_excute_data)`不為NULL,我們正在執行某事。

EG(異常)EG(prev_exception) - 被轉換為指向zend_object的指針,以前它們是指向zval的指針。

Opcodes changes

ZEND_DO_FCALL_BY_NAME - 已刪除, ZEND_INIT_FCALL_BY_NAME已添加。

ZEND_BIND_GLOBAL - 被添加到處理“全局$ var”

ZEND_STRLEN - 已添加以替換strlen函數

ZEND_TYPE_CHECK - 已添加以替換is_array / is_int / is_ *(如果可能)

ZEND_DEFINED - 被添加來替換zif_defined如果可能(如果只有一個參數,它的常量字符串,它不在命名空間樣式)

ZEND_SEND_VAR_EX - 是為了做比 ZEND_SEND_VAR更多的檢查,如果條件無法在編譯時間內解決

ZEND_SEND_VAL_EX - 已添加,以進行比 ZEND_SEND_VAL更多的檢查,如果條件無法在編譯時間內解決

ZEND_INIT_USER_CALL - 被添加以替換call_user_func(_array)如果可能的話,如果在編譯時無法找到該函數,否則它可以轉換為 ZEND_INIT_FCALL

ZEND_SEND_ARRAY - 被添加發送第二個參數,call_user_func_array的數組在被轉換為操作碼

ZEND_SEND_USER - 被添加以發送call_user_func的參數,在它被轉換為操作碼之后

temp_variable PCRE

一些pcre API使用或返回zend_string現在。 F.e. php_pcre_replace返回一個zend_string,并將zend_string作為第一個參數。 仔細檢查他們的聲明以及編譯器警告,這很可能是錯誤的參數類型。

phpng-upgrading.txt · Last modified: 2016/01/21 17:18 by nikic

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/22149.html

相關文章

  • PHP 7 新特征

    摘要:本次發布標志著新的重要的系列的開始。經過社區投票,新項目命名為。結果如下結果如下四新特性標量類型聲明有兩種模式強制默認和嚴格模式。已廢棄的和函數已被移除。在中,如果發生這種情況,會引發錯誤,并且返回。 最好的語言發布了新的版本,一個劃時代的大版本:PHP7。 PHP7修復了大量BUG,新增了功能和語法糖。這些改動涉及到了核心包、GD庫、PDO、ZIP、ZLIB等熟悉和不熟悉的核心功能與...

    Channe 評論0 收藏0
  • 安裝php7,與php5共存

    摘要:安裝源碼在下載并解壓。為不與沖突,文件夾都用,安裝過程中報錯的安裝響應的依賴。啟動中途如遇到日志文件路徑不存在就手動創建并給予寫的權限。遇到這個錯誤時,要添加個組再重新啟動。的配置這是訪問文件是變成下載文件,因為并未配置響應處理。 起步 之前在服務器搭建了lamp環境,想換用性能更強的nginx作為服務器軟件,又想將php5升級為php7.安裝nginx無需贅述:sudo apt-ge...

    TalkingData 評論0 收藏0
  • PHP7新特性的介紹

    摘要:截止到目前為止,官方已經發布了的版本,距離發布第一個正式版本不會很遠了現在來說的重大特性肯定已經是定型了,不會再有什么變動了。 截止到目前為止,PHP官方已經發布了php7的RC7版本,距離發布第一個正式版本不會很遠了!現在來說php7的重大特性肯定已經是定型了,不會再有什么變動了。后續一些版本的迭代主要也就是修修bug,優化之類的。下面就來說話我們一直期待的php7會有那些主要的變化...

    klivitamJ 評論0 收藏0
  • 項目切換PHP7.1.15

    摘要:也可以接入項目打包測試流程做代碼檢測。擴展替換以后廢棄了和擴展,項目中使用的使用的類使用的是已經廢棄的擴展使用擴展做兼容替換。測試方案和大部分公司差不多,項目組劃分了線下開發環境預發布環境和生產環境三個環境。 項目由PHP5.5切換至PHP7.1.15 背景 從2015年鳥哥的技術分享,我們知道PHP7是對底層實現得一次完全重構,函數調用機制和內存管理等很多方便做了優化,使PHP性能有...

    tuniutech 評論0 收藏0
  • 如何把擴展PHP5升級PHP7

    摘要:所以,分配內存的宏都被刪掉了。為的輪詢設計了一組宏,使用起來非常方便。 我在公司的生產環境已經升級了PHP7,大部分活躍的擴展都可以兼容PHP7或者有了PHP7的分支,但是處理protocolbuffers數據的擴展一直沒有人來升級,我只能摸著石頭過河,自己做一把升級了。目前已經編譯通過,處在處理單測失敗的case階段,歡迎大家一起討論。對PHP擴展升級可以先看一下官方的升級說明,ht...

    AWang 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<