首頁 後端開發 PHP8 解析PHP8底層內核源碼-數組(四)

解析PHP8底層內核源碼-數組(四)

Jun 10, 2021 pm 03:08 PM
php8 陣列

本篇文章為大家介紹《解析PHP8底層核心原始碼-陣列(四)》。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

相關文章推薦:《解析PHP8底層核心源碼-陣列(一)》《解析PHP8底層核心原始碼-陣列(二)》《解析PHP8底層核心原始碼-陣列(三)

在Runningprocess 裡已經知道程式碼需要經過詞法分析語法分析編譯執行四大步驟

PHP 8會在編譯階段(將AST抽象語法樹編譯成opcode時)就建立一個陣列常數。這個陣列常數和數字常數、字串常數一樣,是在編譯階段就確定並分配記憶體的。因此數組的初始化發生在編譯階段。

PHP的陣列初始化程式碼部分如下

//如果开启zend_debug 
#if !ZEND_DEBUG && defined(HAVE_BUILTIN_CONSTANT_P)
# define zend_new_array(size) \
(__builtin_constant_p(size) ? \
((((uint32_t)(size)) <= HT_MIN_SIZE) ? \
_zend_new_array_0() \
//走 _zend_new_array_0
: \
_zend_new_array((size)) \
) \
: \
_zend_new_array((size)) \
)
#else
//没有开启 也就是一般模式 走 _zend_new_array
# define zend_new_array(size) \
_zend_new_array(size)
#endif
ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent)
{
_zend_hash_init_int(ht, nSize, pDestructor, persistent);
}
ZEND_API HashTable* ZEND_FASTCALL _zend_new_array_0(void)
{        //分配内存空间
HashTable *ht = emalloc(sizeof(HashTable));
         //初始化
_zend_hash_init_int(ht, HT_MIN_SIZE, ZVAL_PTR_DTOR, 0);
return ht;
}
//初始化方法
static zend_always_inline void _zend_hash_init_int(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent)
{
GC_SET_REFCOUNT(ht, 1);
GC_TYPE_INFO(ht) = GC_ARRAY | (persistent ? ((GC_PERSISTENT|GC_NOT_COLLECTABLE) << GC_FLAGS_SHIFT) : 0);
HT_FLAGS(ht) = HASH_FLAG_UNINITIALIZED;
ht->nTableMask = HT_MIN_MASK;
HT_SET_DATA_ADDR(ht, &uninitialized_bucket);
ht->nNumUsed = 0;
ht->nNumOfElements = 0;
ht->nInternalPointer = 0;
ht->nNextFreeElement = ZEND_LONG_MIN;
ht->pDestructor = pDestructor;
ht->nTableSize = zend_hash_check_size(nSize);
}
//初始化 bucket 也就是 ardata
ZEND_API void ZEND_FASTCALL zend_hash_real_init(HashTable *ht, zend_bool packed)
{
IS_CONSISTENT(ht);
HT_ASSERT_RC1(ht);
//调用 zend_hash_real_init_ex方法
zend_hash_real_init_ex(ht, packed);
}
//zend_hash_real_init_ex方法
static zend_always_inline void zend_hash_real_init_ex(HashTable *ht, bool packed)
{
HT_ASSERT_RC1(ht);
ZEND_ASSERT(HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED);
if (packed) {
//如果是packed_array 
zend_hash_real_init_packed_ex(ht);
} else {
//如果是 hash_array
zend_hash_real_init_mixed_ex(ht);
}
}
//paced_array 初始化bucket 的代码
static zend_always_inline void zend_hash_real_init_packed_ex(HashTable *ht)
{
void *data;
if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) {
data = pemalloc(HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK), 1);
} else if (EXPECTED(ht->nTableSize == HT_MIN_SIZE)) {
data = emalloc(HT_SIZE_EX(HT_MIN_SIZE, HT_MIN_MASK));
} else {
data = emalloc(HT_SIZE_EX(ht->nTableSize, HT_MIN_MASK));
}
HT_SET_DATA_ADDR(ht, data);
/* Don&#39;t overwrite iterator count. */
ht->u.v.flags = HASH_FLAG_PACKED | HASH_FLAG_STATIC_KEYS;
HT_HASH_RESET_PACKED(ht);
}
//hash_array 初始化bucket的代码
static zend_always_inline void zend_hash_real_init_mixed_ex(HashTable *ht)
{
void *data;
uint32_t nSize = ht->nTableSize;
if (UNEXPECTED(GC_FLAGS(ht) & IS_ARRAY_PERSISTENT)) {
data = pemalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)), 1);
} else if (EXPECTED(nSize == HT_MIN_SIZE)) {
data = emalloc(HT_SIZE_EX(HT_MIN_SIZE, HT_SIZE_TO_MASK(HT_MIN_SIZE)));
ht->nTableMask = HT_SIZE_TO_MASK(HT_MIN_SIZE);
HT_SET_DATA_ADDR(ht, data);
/* Don&#39;t overwrite iterator count. */
ht->u.v.flags = HASH_FLAG_STATIC_KEYS;
#ifdef __SSE2__
do {
__m128i xmm0 = _mm_setzero_si128();
xmm0 = _mm_cmpeq_epi8(xmm0, xmm0);
_mm_storeu_si128((__m128i*)&HT_HASH_EX(data,  0), xmm0);
_mm_storeu_si128((__m128i*)&HT_HASH_EX(data,  4), xmm0);
_mm_storeu_si128((__m128i*)&HT_HASH_EX(data,  8), xmm0);
_mm_storeu_si128((__m128i*)&HT_HASH_EX(data, 12), xmm0);
} while (0);
#elif defined(__aarch64__)
do {
int32x4_t t = vdupq_n_s32(-1);
vst1q_s32((int32_t*)&HT_HASH_EX(data,  0), t);
vst1q_s32((int32_t*)&HT_HASH_EX(data,  4), t);
vst1q_s32((int32_t*)&HT_HASH_EX(data,  8), t);
vst1q_s32((int32_t*)&HT_HASH_EX(data, 12), t);
} while (0);
#else
HT_HASH_EX(data,  0) = -1;
HT_HASH_EX(data,  1) = -1;
HT_HASH_EX(data,  2) = -1;
HT_HASH_EX(data,  3) = -1;
HT_HASH_EX(data,  4) = -1;
HT_HASH_EX(data,  5) = -1;
HT_HASH_EX(data,  6) = -1;
HT_HASH_EX(data,  7) = -1;
HT_HASH_EX(data,  8) = -1;
HT_HASH_EX(data,  9) = -1;
HT_HASH_EX(data, 10) = -1;
HT_HASH_EX(data, 11) = -1;
HT_HASH_EX(data, 12) = -1;
HT_HASH_EX(data, 13) = -1;
HT_HASH_EX(data, 14) = -1;
HT_HASH_EX(data, 15) = -1;
#endif
return;
} else {
data = emalloc(HT_SIZE_EX(nSize, HT_SIZE_TO_MASK(nSize)));
}
ht->nTableMask = HT_SIZE_TO_MASK(nSize);
HT_SET_DATA_ADDR(ht, data);
HT_FLAGS(ht) = HASH_FLAG_STATIC_KEYS;
HT_HASH_RESET(ht);
}
//数组赋值和更新值
static zend_always_inline zval *_zend_hash_index_add_or_update_i(HashTable *ht, zend_ulong h, zval *pData, uint32_t flag)
{
uint32_t nIndex;
uint32_t idx;
Bucket *p;
IS_CONSISTENT(ht);
HT_ASSERT_RC1(ht);
if ((flag & HASH_ADD_NEXT) && h == ZEND_LONG_MIN) {
h = 0;
}
if (HT_FLAGS(ht) & HASH_FLAG_PACKED) {
if (h < ht->nNumUsed) {
p = ht->arData + h;
if (Z_TYPE(p->val) != IS_UNDEF) {
replace:
if (flag & HASH_ADD) {
return NULL;
}
if (ht->pDestructor) {
ht->pDestructor(&p->val);
}
ZVAL_COPY_VALUE(&p->val, pData);
return &p->val;
} else { /* we have to keep the order :( */
goto convert_to_hash;
}
} else if (EXPECTED(h < ht->nTableSize)) {
add_to_packed:
p = ht->arData + h;
/* incremental initialization of empty Buckets */
if ((flag & (HASH_ADD_NEW|HASH_ADD_NEXT)) != (HASH_ADD_NEW|HASH_ADD_NEXT)) {
if (h > ht->nNumUsed) {
Bucket *q = ht->arData + ht->nNumUsed;
while (q != p) {
ZVAL_UNDEF(&q->val);
q++;
}
}
}
ht->nNextFreeElement = ht->nNumUsed = h + 1;
goto add;
} else if ((h >> 1) < ht->nTableSize &&
           (ht->nTableSize >> 1) < ht->nNumOfElements) {
zend_hash_packed_grow(ht);
goto add_to_packed;
} else {
if (ht->nNumUsed >= ht->nTableSize) {
ht->nTableSize += ht->nTableSize;
}
convert_to_hash:
zend_hash_packed_to_hash(ht);
}
} else if (HT_FLAGS(ht) & HASH_FLAG_UNINITIALIZED) {
if (h < ht->nTableSize) {
zend_hash_real_init_packed_ex(ht);
goto add_to_packed;
}
zend_hash_real_init_mixed(ht);
} else {
if ((flag & HASH_ADD_NEW) == 0 || ZEND_DEBUG) {
p = zend_hash_index_find_bucket(ht, h);
if (p) {
ZEND_ASSERT((flag & HASH_ADD_NEW) == 0);
goto replace;
}
}
ZEND_HASH_IF_FULL_DO_RESIZE(ht);/* If the Hash table is full, resize it */
}
idx = ht->nNumUsed++;
nIndex = h | ht->nTableMask;
p = ht->arData + idx;
Z_NEXT(p->val) = HT_HASH(ht, nIndex);
HT_HASH(ht, nIndex) = HT_IDX_TO_HASH(idx);
if ((zend_long)h >= ht->nNextFreeElement) {
ht->nNextFreeElement = (zend_long)h < ZEND_LONG_MAX ? h + 1 : ZEND_LONG_MAX;
}
add:
ht->nNumOfElements++;
p->h = h;
p->key = NULL;
ZVAL_COPY_VALUE(&p->val, pData);
return &p->val;
}
登入後複製

_zend_hash_init_int 流程圖如下

解析PHP8底層內核源碼-數組(四)
_zend_hash_init_int方法流程圖(初始化hash)
解析PHP8底層內核源碼-數組(四)
zend_hash_real_init_ex方法流程圖(初始化bucket)


#在PHP 8中,陣列的初始化其實是分兩步驟的。

第1步:分配HashTable結構體記憶體

第2步:  初始化HashTable結構體各個字段

第3步:分配bucket數組內存,修改一些字段值。

對於第3步,並不是每次都進行。例如像「$a = array()」這種寫法,由於陣列為空,PHP 不會額外申請bucket陣列記憶體。而對於「$a = array(1, 2, 3)」這種寫法,由於數組非空,因此PHP 需要執行第3步  分配bucket數組內存,並修改一些字段值。

解析PHP8底層內核源碼-數組(四)


解析PHP8底層內核源碼-數組(四)
zend_hash_real_init_packed_ex(當為packed_array 時候bucket的初始化流程圖)
解析PHP8底層內核源碼-數組(四)
zend_hash_real_init_mixed_ex 初始化為hash_array bucket的流程圖

###################################################################################################################################################################################################### ####▏本文經原作者PHP崔雪峰同意,發佈在php中文網,原文網址:https://zhuanlan.zhihu.com/p/361006441##########

以上是解析PHP8底層內核源碼-數組(四)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前 By 尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前 By 尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱門文章標籤

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何使用 foreach 迴圈移除 PHP 陣列中的重複元素? 如何使用 foreach 迴圈移除 PHP 陣列中的重複元素? Apr 27, 2024 am 11:33 AM

如何使用 foreach 迴圈移除 PHP 陣列中的重複元素?

PHP 陣列鍵值翻轉:不同方法的效能比較分析 PHP 陣列鍵值翻轉:不同方法的效能比較分析 May 03, 2024 pm 09:03 PM

PHP 陣列鍵值翻轉:不同方法的效能比較分析

PHP數組多維排序實戰:從簡單到複雜場景 PHP數組多維排序實戰:從簡單到複雜場景 Apr 29, 2024 pm 09:12 PM

PHP數組多維排序實戰:從簡單到複雜場景

PHP數組深度複製的藝術:使用不同方法完美複製 PHP數組深度複製的藝術:使用不同方法完美複製 May 01, 2024 pm 12:30 PM

PHP數組深度複製的藝術:使用不同方法完美複製

深度複製PHP數組的最佳實踐:探索高效的方法 深度複製PHP數組的最佳實踐:探索高效的方法 Apr 30, 2024 pm 03:42 PM

深度複製PHP數組的最佳實踐:探索高效的方法

PHP 數組分組函數在資料整理的應用 PHP 數組分組函數在資料整理的應用 May 04, 2024 pm 01:03 PM

PHP 數組分組函數在資料整理的應用

PHP 陣列分組函數在尋找重複元素中的作用 PHP 陣列分組函數在尋找重複元素中的作用 May 05, 2024 am 09:21 AM

PHP 陣列分組函數在尋找重複元素中的作用

PHP 數組合併去重演算法:平行的解決方案 PHP 數組合併去重演算法:平行的解決方案 Apr 18, 2024 pm 02:30 PM

PHP 數組合併去重演算法:平行的解決方案

See all articles