我们注意到
, 最后一个元素, 这个是 flexible
array
技巧
, 可以节省内存,和方便初始化的一种做
法
, 有兴趣的朋友可以 google flexible
array
.
h 是元素的 Hash 值,对于数字索引的元素,h 为直接索引值(通过 nKeyLength=0 来表示是数字
索引
).而对于字符串索引来说, 索引值保存在 arKey 中, 索引的长度保存在 nKeyLength 中.
在
Bucket 中,实际的数据是保存在 pData 指针指向的内存块中,通常这个内存块是系统另
外分配的。但有一种情况例外,就是当
Bucket 保存 的数据是一个指针时,HashTable 将不会
另外请求系统分配空间来保存这个指针,而是直接将该指针保存到
pDataPtr 中,然后再将
pData 指向本结构成员的地址。这样可以提高效率,减少内存碎片。由此我们可以看到 PHP
HashTable 设计的精妙之处。如果 Bucket 中的数据不是一个指针,pDataPtr 为 NULL(本段来
自
Altair 的”Zend HashTable 详解”)
结合上面的
HashTable 结构, 我们来说明下 HashTable 的总结构图:
HashTable 的 pListhHead 指向线性列表形式下的第一个元素, 上图中是元素 1, pListTail 指向
的是最后一个元素
0, 而对于每一个元素 pListNext 就是红色线条画出的线性结构的下一个
元素
, 而 pListLast 是上一个元素.
pInternalPointer 指向当前的内部指针的位置, 在对数组进行顺序遍历的时候, 这个指针指明
了当前的元素
.
当在线性
(顺序)遍历的时候, 就会从 pListHead 开始, 顺着 Bucket 中的 pListNext/pListLast, 根
据移动
pInternalPointer, 来实现对所有元素的线性遍历.
比如
, 对于
foreach
, 如果我们查看它生成的 opcode 序列, 我们可以发现, 在
foreach
之前
, 会首
先有个
FE_RESET 来重置数组的内部指针, 也就是 pInternalPointer(关于
foreach
可以参看深
入理解
PHP 原理之
foreach
), 然后通过每次 FE_FETCH 来递增 pInternalPointer,从而实现顺序