摘要:所以,分配內存的宏都被刪掉了。為的輪詢設計了一組宏,使用起來非常方便。
我在公司的生產環境已經升級了PHP7,大部分活躍的擴展都可以兼容PHP7或者有了PHP7的分支,但是處理protocolbuffers數據的擴展一直沒有人來升級,我只能摸著石頭過河,自己做一把升級了。目前已經編譯通過,處在處理單測失敗的case階段,歡迎大家一起討論。對PHP擴展升級可以先看一下官方的升級說明,https://wiki.php.net/phpng-upgrading,基本可以應對大部分場景,剩下的就需要自己讀源代碼了。
zvalzval結構體是Zend內核的非常核心的結構,在PHP5和PHP7之間的差別非常大,我給出2處文章供大家學習,基本上可以代表這塊知識點最權威的介紹了。
深入理解PHP7之zval(鳥哥)
https://github.com/laruence/php7-internal/blob/master/zval.md
變量在 PHP7 內部的實現(Nikita Popov)中文版
http://0x1.im/blog/php/Internal-value-representation-in-PHP-7-part-1.html
http://0x1.im/blog/php/Internal-value-representation-in-PHP-7-part-2.html
PHP7不再使用zval的二級指針,大多數場景下出現的zval*變量都改成zval,相應的使用在這些變量上的宏Z_PP也需要改成Z_P。
在大部分場景下,PHP7是在棧上直接使用zval,不需要去堆上分配內存。這時,zval 就需要改成zval,宏也需要從Z__P改成Z_,創建宏從ZVAL_(var)轉換成ZVAL_*(&var)。所以,分配zval內存的宏
ALLOC_ZVAL、ALLOC_INIT_ZVAL、MAKE_STD_ZVAL都被刪掉了。 - zval *zv; - MAKE_STD_ZVAL(zv); - array_init(zv); + zval zv; + array_init(&zv);
PHP7中zval的long和double類型是不需要引用計數的,所以相關的宏要做調整。
- Z_ADDREF_P(zv) + Z_TRY_ADDREF_P(zv);
PHP7中zval的類型,刪除了IS_BOOL,增加了IS_TRUE和IS_FALSE。
- if (Z_TYPE_P(zv) == IS_BOOL) { - } + if (Z_TYPE_P(zv) == IS_TRUE) { + } else if (Z_TYPE_P(zv) == IS_FALSE) { + }zend_string
PHP7中增加了一個新的內置字符串類型zend_string,下面是Zend內核中的結構體定義。
struct _zend_string { zend_refcounted_h gc; /* 垃圾回收結構體 */ zend_ulong h; /* 字符串哈希值 */ size_t len; /* 字符串長度 */ char val[1]; /* 字符串內容 */ };
gc是PHP7中的所有非標量結構都包含的垃圾回收結構體變量;h是字符串哈希值,作為HashTable的key時不需要每次都重新計算哈希值,提高了效率;len是字符串長度,同理每次使用到字符串的長度時不需要再計算,提高了效率;val[1]是C語言的黑科技,此處按照char *理解即可。這里有三個宏幫助我們方便的使用zend_string的變量。
#define ZSTR_VAL(zstr) (zstr)->val #define ZSTR_LEN(zstr) (zstr)->len #define ZSTR_H(zstr) (zstr)->h
創建和銷毀zend_string使用以下方法。
zend_string *zend_string_init(const char *str, size_t len, int persistent) void zend_string_release(zend_string *s)
zend_string用來替代PHP5中使用char *和int的場景,尤其是很多API的參數和返回值都做了調整。
- int zend_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData) + zval* ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key) - void zend_mangle_property_name(char **dest, int *dest_length, const char *src1, int src1_length, const char *src2, int src2_length, int internal); + zend_string *zend_mangle_property_name(const char *src1, size_t src1_length, const char *src2, size_t src2_length, int internal)HashTable API
在PHP7中使用HashTable的API方法時,有了非常明顯的變化。
查詢方法,PHP5使用引用傳參的方式,同時返回SUCCESS/FAILURE;PHP7直接返回結果,查詢無結果時返回NULL。
- int zend_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData) + zval* ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
HashTable的API方法中的key,PHP5中使用char 和int代表的字符串;PHP7中使用zend_string代表的字符串,同時提供了對char 和int支持的一組方法,但是需要注意的是這里的字符串長度是不包括結尾的"0"的,在升級擴展時難免會碰到很多地方需要加減一。
- int zend_hash_exists(const HashTable *ht, const char *arKey, uint nKeyLength) + zend_bool zend_hash_exists(const HashTable *ht, zend_string *key) + zend_bool zend_hash_str_exists(const HashTable *ht, const char *str, size_t len)
PHP7為HashTable的value為指針時設計了一組API,在常規的API方法后添加后綴_ptr即可。
void *zend_hash_find_ptr(const HashTable *ht, zend_string *key) void *zend_hash_update_ptr(HashTable *ht, zend_string *key, void *pData)
PHP7為HashTable的輪詢設計了一組宏,使用起來非常方便。
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)自定義對象
這里有點復雜,我直接附上我的代碼,結合代碼來做詳細說明。
typedef struct{ int max; int offset; zend_object zo; } php_protocolbuffers_unknown_field_set; static zend_object_handlers php_protocolbuffers_unknown_field_set_object_handlers; static void php_protocolbuffers_unknown_field_set_free_storage(php_protocolbuffers_unknown_field_set *object TSRMLS_DC) { php_protocolbuffers_unknown_field_set *unknown_field_set; unknown_field_set = (php_protocolbuffers_unknown_field_set*)((char *) object - XtOffsetOf(php_protocolbuffers_unknown_field_set, zo)); zend_object_std_dtor(&unknown_field_set->zo TSRMLS_CC); } zend_object *php_protocolbuffers_unknown_field_set_new(zend_class_entry *ce TSRMLS_DC) { php_protocolbuffers_unknown_field_set *intern; intern = ecalloc(1, sizeof(php_protocolbuffers_unknown_field_set) + zend_object_properties_size(ce)); zend_object_std_init(&intern->zo, ce); object_properties_init(&intern->zo, ce); intern->zo.handlers = &php_protocolbuffers_unknown_field_set_object_handlers; intern->max = 0; intern->offset = 0; return &intern->zo; } void php_protocolbuffers_unknown_field_set_class(TSRMLS_D) { // 此處有省略 php_protocol_buffers_unknown_field_set_class_entry->create_object = php_protocolbuffers_unknown_field_set_new; memcpy(&php_protocolbuffers_unknown_field_set_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); php_protocolbuffers_unknown_field_set_object_handlers.offset = XtOffsetOf(php_protocolbuffers_unknown_field_set, zo); php_protocolbuffers_unknown_field_set_object_handlers.free_obj = php_protocolbuffers_unknown_field_set_free_storage; }
我們想自定義一個php_protocolbuffers_unknown_field_set的對象,在它的結構體里面除了zend_object,還有自定義的max和offset,務必把zend_object放在最后。
實際生成對象的地方基本就是標準寫法,先分配內存,包括php_protocolbuffers_unknown_field_set結構體的內存和對象屬性的內存;然后對zend_object的handlers賦值;最后再對自己自定義的變量初始化。
實際生成對象handler的地方也是標準寫法,先分配內存,offset是必須設置的,可選的設置項有free_obj,dtor_obj,clone_obj。
想取到zend_object,需要(STRUCT_NAME )((char )OBJECT - XtOffsetOf(STRUCT_NAME, zo))
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/21598.html
摘要:也可以接入項目打包測試流程做代碼檢測。擴展替換以后廢棄了和擴展,項目中使用的使用的類使用的是已經廢棄的擴展使用擴展做兼容替換。測試方案和大部分公司差不多,項目組劃分了線下開發環境預發布環境和生產環境三個環境。 項目由PHP5.5切換至PHP7.1.15 背景 從2015年鳥哥的技術分享,我們知道PHP7是對底層實現得一次完全重構,函數調用機制和內存管理等很多方便做了優化,使PHP性能有...
摘要:可以理解為的吧升級到之后,測試環境測試的時候發現直接調用庫函數的地方報錯了。問題解決查看了代碼和資料才知道原來上是默認安裝的,而上的默認安裝是不安裝的擴展的,是會默認支持的,就是可以直接調用。參考資料官網說明其實是第一條的用戶評論里面 問題描述: ????原本公司使用的是php5.6,然后因為一些原因要升級到php7,然后代碼中有一些地方使用到了bcmath(就是用來進行任意精度的計算...
摘要:我們為了處理這些挑戰,提出了一個新的引用測試框架當然,也是開源的,并且在整個過程中節省了上百萬美元。另一方面,被證實有一些嚴重的缺點部署困難而且慢。在緩存刷新期間,當可用于別的進程的已緩存的文件字節碼在此時損壞,就會導致崩潰。 How Badoo saved one million dollars switching to PHP7 我們成功的把我們的應用遷移到了php7上面(數百臺機...
閱讀 2749·2021-10-09 09:44
閱讀 3557·2019-08-30 15:54
閱讀 2168·2019-08-30 14:16
閱讀 2801·2019-08-30 13:09
閱讀 831·2019-08-30 13:08
閱讀 1291·2019-08-29 16:29
閱讀 1678·2019-08-26 13:57
閱讀 1934·2019-08-26 13:53