php数组实现的原理

前言

本文采用的php版本是7.4.3

另外在了解数组实现前,需要知道zval是什么,如果不知道zval是什么,可以来我的这篇文章看下
https://blog.csdn.net/onlymayao/article/details/104783731

zend_array是什么

php的array类型就是对应的zend_array

zend_array的结构

typedef struct _zend_array      zend_array; //首先这是一个结构体
typedef struct _zend_array HashTable;   //还定义了一个别名hashtable

//下面来看这个里面定义的什么
struct _zend_array {
        zend_refcounted_h gc;
        union {
                struct {
                        ZEND_ENDIAN_LOHI_4(
                                zend_uchar    flags,
                                zend_uchar    _unused,
                                zend_uchar    nIteratorsCount,
                                zend_uchar    _unused2)
                } v;
                uint32_t flags;
        } u;
        uint32_t          nTableMask;
        Bucket           *arData;
        uint32_t          nNumUsed;
        uint32_t          nNumOfElements;
        uint32_t          nTableSize;
        uint32_t          nInternalPointer;
        zend_long         nNextFreeElement;
        dtor_func_t       pDestructor;
};

zend_array块解析

gc:垃圾回收机制
nTableMask:用来计算索引值
arData:这个里面存储的是key、value对
nNumUsed:表示我已经用了的空间,包含跳过去的,比如我一个数组长度是8,我跳过下标0,直接给下标1赋值,此时的nNumUsed是2.
nNumOfElements:表示真正的元素的个数,结合上个字段的例子,这个值是1
nTableSize:代表arData的大小
nNextFreeElement:这个值主要用在当我们往数组中push数据而不指定下标的时候,比如说$arr[]=1,这个下标值就会从nNextFreeElement拿

需要了解的其他点

hashtable分为packed array 和hash array;
关于packed array:

  1. 对于key是数字的,就不用涉及到hash运算,此时使用的是packed array
  2. 当然如果key的值较大,或者间隔较大,还是会退化成hash array。
  3. packed array 能够节省索引部分占用的内存,是一个性能上的优化;
  4. 此时索引数组只用了-1和-2

关于hash array:

  1. 对于key是非数字的,必须用hash算法进行计算出来它所在bucket的位置,那么索引数组是必不可少的,只能是hash array。
/*
 * HashTable Data Layout
 * =====================
 *
 *                 +=============================+
 *                 | HT_HASH(ht, ht->nTableMask) |
 *                 | ...                         |
 *                 | HT_HASH(ht, -1)             |
 *                 +-----------------------------+
 * ht->arData ---> | Bucket[0]                   |
 *                 | ...                         |
 *                 | Bucket[ht->nTableSize-1]    |
 *                 +=============================+
 */

涉及到的面试知识点

问题1:对于一个数组,他初始的大小是多少
答:初始时候的nTableSize是8

问题2:当我们的数组不够用的时候怎么办
答:会进行扩容

问题3:数组每次扩容的大小是多少
答:会在原来的基础上乘以2,比如说8变成16、16变成32,以此类推

问题4:如何解决hash冲突
答:链地址法;主要用zval块中u2.next这个字段来解决hash冲突,前面讲zval的时候咱们提过,不知道大家是否还有印象。

问题5:如何知道bucket的值存放在索引数组的哪个下标
答:对于一个nTableSize为8的数组,此时它的nTableMask是-8,如果我们知道他的hashvalue值是0,那么hashvalue | nTableMask 也就是 0 | -8 得到 -8 就是存放bucket的位置

问题6:解决hash冲突是头插法还是尾插法
答:头插法

问题7:数组除了用在$arr=[],还用在了哪些地方
答:生命周期、虚拟机、内核

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值