一、hashArray vs packedArray
- $arr1 是packed arrray 本身就是有顺序的
- $arr2 是hash array需要做散列来保证数组的存取顺序
-
$arr1 = []; for ($i = 0; $i <= 200000; $i++) { $arr1[$i] = $i; } $arr2 = []; for ($i = 200000; $i >= 0; $i--) { $arr2[$i] = $i; }
-
- $arr2 比$arr1 多占用的内存为图示用于做散列的部分
- 默认8个bucket,如果索引数组的下标不超过8使用packed array存储即可,留出空余位置即可。超过8为了不浪费空间,会转化为hash array
-
<?php $a = [1, 2, 3]; $a[5] = 5; echo $a; $b = [1, 2, 3]; $b[10] = 10; echo $b;
-
二、数组hashTable
解决hash冲突:拉链法(头插法,不用遍历)
问题:冲突过多时时间复杂度会有O1降到On
解决方法:rehash,把链表换成红黑树等其他数据结构
三、zval复杂类型的gc都会存一下类型
空间换时间
不知道类型的变量可强转gc,直接拿到类型
四、php的数组类型
typedef struct _zend_array HashTable;
struct _zend_array {
zend_refcounted_h gc; // 垃圾回收,应用计数
union u;
uint32_t nTableMask;// 用来做散列
Bucket *arData; // 存key-value对的桶
uint32_t nNumUsed; // 元素个数,unset不会减少
uint32_t nNumOfElements; // 真正有意义的元素个数,unset会减少
uint32_t nTableSize; // 大小,默认8,不够用两倍扩容
uint32_t nInternalPointer;
zend_long nNextFreeElement; // 当前已用的数组下标
dtor_func_t pDestructor;
};
typedef struct _Bucket {
zval val; // 任意类型zval
zend_ulong h; // packed array
zend_string *key; // hash array
} Bucket;
五、PHP中的HashTable
- php7采用逻辑链表解决hash冲突
- 计算hash array 槽的方式:nTableMask 或 key通过的hash算法算出来的hash值
六、gdb 查看PHP中的HashTable(set print pretty on 可显示格式化的数据)
$a = [];
echo $a;
$a['k1'] = 'v1';
echo $a;
$a[] = 1;
echo $a;
$a[] = 2;
echo $a;
$a[] = 3;
echo $a;
unset($a[0]);
echo $a;
$a[5] = 5;
echo $a;
- 初始化$a=[];
- 添加第一个元素$a['k1'] = 'v1';
- 添加第二个元素$a[] = 1;
- 添加第三个元素$a[] = 2;
- 添加第四个元素$a[] = 3;
- 删除第二个元素unset($a[0]);
- 增加第五个元素$a[5] = 5;
- 增加第六个元素$a['6'] = 6;