Heim > Backend-Entwicklung > PHP8 > Parsen des zugrunde liegenden PHP8-Kernel-Quellcodes – Array (4)

Parsen des zugrunde liegenden PHP8-Kernel-Quellcodes – Array (4)

藏色散人
Freigeben: 2023-02-17 12:04:01
nach vorne
3040 Leute haben es durchsucht

Dieser Artikel stellt Ihnen „Analyse des zugrunde liegenden PHP8-Kernel-Quellcodes – Array (4)“ vor. Es hat einen gewissen Referenzwert. Freunde in Not können sich darauf beziehen. Ich hoffe, es wird für alle hilfreich sein.

Empfohlene verwandte Artikel: „Analyse des PHP8 zugrunde liegenden Kernel-Quellcodes – Array (1)“ „Analyse des PHP8 zugrunde liegenden Kernel-Quellcodes – Array (2)“ „Analyse des PHP8 zugrunde liegenden Kernel-Quellcodes – Array ( 3)"

In Runningprocess wissen wir bereits, dass der Code eine lexikalische Analyse, Syntaxanalyse, Kompilierung und Ausführung von vier Hauptschritten durchlaufen muss

PHP 8 befindet sich in der Kompilierungsphase (wenn der abstrakte AST-Syntaxbaum in Opcode kompiliert wird) und erstellt eine Array-Konstante. Diese Array-Konstante wird, ebenso wie numerische Konstanten und String-Konstanten, während der Kompilierungsphase bestimmt und Speicher zugewiesen. Die Initialisierung des Arrays erfolgt also während der Kompilierungsphase.

Der Array-Initialisierungscodeteil von PHP lautet wie folgt:

//如果开启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;
}
Nach dem Login kopieren

_zend_hash_init_int Das Flussdiagramm lautet wie folgt: Flussdiagramm der Methode_zend_hash_init_int (Initialisierungs-Hash)

Parsen des zugrunde liegenden PHP8-Kernel-Quellcodes – Array (4)
zend_hash_real_init_ex Methodenablaufdiagramm (Bucket initialisieren). )
Parsen des zugrunde liegenden PHP8-Kernel-Quellcodes – Array (4)In PHP 8 ist die Initialisierung von Arrays eigentlich in zwei Schritte unterteilt.
Schritt 1: HashTable-Strukturspeicher zuweisen

Schritt 2: Jedes Feld der HashTable-Struktur initialisieren

Schritt 3: Bucket-Array-Speicher zuweisen und einige Feldwerte ändern.

Bei Schritt 3 wird dies nicht jedes Mal durchgeführt. Da das Array beispielsweise leer ist, beantragt PHP bei „$a = array()“ keinen zusätzlichen Bucket-Array-Speicher. Für die Schreibmethode „$a = array(1, 2, 3)“ muss PHP Schritt 3 ausführen, um Bucket-Array-Speicher zuzuweisen und einige Feldwerte zu ändern, da das Array nicht leer ist.

Parsen des zugrunde liegenden PHP8-Kernel-Quellcodes – Array (4)


zend_hash_real_init_packed_ex (Bucket-Initialisierungsflussdiagramm, wenn gepacktes_Array)

Parsen des zugrunde liegenden PHP8-Kernel-Quellcodes – Array (4)
zend_hash_real_init_mixed_ex-Flussdiagramm, initialisiert im hash_array-Bucket
Parsen des zugrunde liegenden PHP8-Kernel-Quellcodes – Array (4)

Das obige ist der detaillierte Inhalt vonParsen des zugrunde liegenden PHP8-Kernel-Quellcodes – Array (4). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:zhihu.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage