搜尋
首頁後端開發PHP8解析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中文網其他相關文章!

陳述
本文轉載於:PHP崔雪峰。如有侵權,請聯絡admin@php.cn刪除

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

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

SublimeText3 Mac版

SublimeText3 Mac版

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

SecLists

SecLists

SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具