php数组的内部实现
PHP 数组的内部实现
PHP 的数组是一种混合数据结构,既支持数字索引也支持字符串键,其内部实现经过多次优化。以下是其核心实现机制:
哈希表(HashTable)
PHP 数组底层使用哈希表(HashTable)实现,通过哈希函数将键映射到存储位置。哈希表由两部分组成:
- 哈希桶(Bucket):存储键值对,包含
key、value和hash值。 - 双向链表:维护插入顺序,保证遍历时按插入顺序输出。
哈希冲突通过链地址法解决,即冲突的键值对以链表形式存储在同一个桶中。

有序性维护
PHP 数组的有序性通过双向链表实现:
- 每个 Bucket 包含
pListLast和pListNext指针,分别指向前驱和后继节点。 - 插入新元素时,会追加到链表尾部,保证
foreach遍历顺序与插入顺序一致。
内存优化
PHP 7 后引入 "Packed Array" 优化:

- 当数组为连续数字索引(如
[0 => 'a', 1 => 'b'])时,直接使用线性存储(类似 C 数组),跳过哈希表操作。 - 若检测到非连续键或字符串键,自动切换回哈希表模式。
动态扩容
哈希表会根据元素数量动态调整容量:
- 初始容量为 8,负载因子超过阈值时扩容为当前大小的 2 倍。
- 扩容时重新哈希所有元素,平衡性能与内存占用。
代码示例
以下是 PHP 内部结构的简化表示(C 语言):
typedef struct _Bucket {
zval val; // 存储的值(PHP 变量)
zend_ulong h; // 哈希值(数字键直接使用)
zend_string *key; // 字符串键
struct _Bucket *next; // 冲突链表指针
} Bucket;
typedef struct _HashTable {
uint32_t nTableSize; // 哈希表大小
Bucket *arData; // 存储桶数组
uint32_t nNumUsed; // 已用桶数
uint32_t nNumOfElements; // 有效元素数
uint32_t nTableMask; // 哈希掩码(nTableSize - 1)
uint32_t nInternalPointer; // 迭代指针
} HashTable;
性能特点
- 查找:平均 O(1) 复杂度,最坏情况 O(n)(哈希冲突严重时)。
- 插入/删除:平均 O(1),但扩容时会有 O(n) 开销。
- 遍历:O(n),依赖双向链表顺序。
使用建议
- 优先使用连续数字索引以触发 Packed Array 优化。
- 避免频繁混合使用数字和字符串键,可能导致哈希表切换开销。
- 大规模数据操作时,预估容量并用
array_pad()预分配空间减少扩容次数。






