首页后端开发PHPphp8底层内核源码之四,数组是什么?

php8底层内核源码之四,数组是什么?

时间2024-03-23 10:40:03发布访客分类PHP浏览1432
导读:关于“php8底层内核源码之四,数组是什么?”的知识点有一些人不是很理解,对此小编给大家总结了相关内容,文中的内容简单清晰,易于学习与理解,具有一定的参考学习价值,希望能对大家有所帮助,接下来就跟随小编一起学习一下“php8底层内核源码之四...
关于“php8底层内核源码之四,数组是什么?”的知识点有一些人不是很理解,对此小编给大家总结了相关内容,文中的内容简单清晰,易于学习与理解,具有一定的参考学习价值,希望能对大家有所帮助,接下来就跟随小编一起学习一下“php8底层内核源码之四,数组是什么?”吧。


 

本篇文章给大家介绍《解析PHP8底层内核源码-数组(四)》。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。

相关文章推荐:《解析PHP8底层内核源码-数组(一)》《解析PHP8底层内核源码-数组(二)》《解析PHP8底层内核源码-数组(三)》

在Runningprocess 里已经知道代码需要经过词法分析 语法分析 编译 执行 四大步骤

  • 《深入解析PHP底层之Running process》

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'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'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 流程图如下

_zend_hash_init_int方法流程图(初始化hash) 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数组内存,修改一些字段值。


zend_hash_real_init_packed_ex(当为packed_array 时候 bucket的初始化流程图) zend_hash_real_init_mixed_ex 初始化为hash_array bucket的流程图

以上就是关于php8底层内核源码之四,数组是什么?的介绍啦,需要的朋友可以参考上述内容,希望对大家有帮助,欢迎关注网络,小编将为大家输出更多高质量的实用文章!

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!

数组

若转载请注明出处: php8底层内核源码之四,数组是什么?
本文地址: https://pptw.com/jishu/651285.html
pandas读取excel文件的方法是什么,如何实现? Python中实现列表转字符串的方法是什么?

游客 回复需填写必要信息