本篇文章给大家介绍《解析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)#endifzend_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 也就是 ardatazend_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_arrayzend_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);#elseht_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;#endifreturn;} 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的流程图▏本文经原作者php崔雪峰同意,发布在,原文地址:https://zhuanlan.zhihu.com/p/361006441
以上就是解析php8底层内核源码-数组(四)的详细内容。