php hashtable nindex,PHP_FUNCTION(extract)和加了注释的hashtable、bucket结构

这个函数功能就是将关联数组展开成这样的变量:$key = val

先用zend_hash_internal_pointer_reset_ex获取头,然后遍历,获取每个元素值zend_hash_get_current_data_ex和键zend_hash_get_current_key_ex,extract有第二参数用来约束已有变量名情况下的各种处理方式,所以还需要判断是否已有同名变量:

zend_hash_exists(EG(active_symbol_table), var_name, var_name_len + 1);

最后注册变量:ZVAL_STRINGL(&final_name, var_name, var_name_len, 1);

值得关注的是这个函数:zend_hash_exists,核心代码如下:

h = zend_inline_hash_func(arKey, nKeyLength);

nIndex = h & ht->nTableMask;

p = ht->arBuckets[nIndex];

while (p != NULL) {

if (p->arKey == arKey ||

((p->h == h) && (p->nKeyLength == nKeyLength) && !memcmp(p->arKey, arKey, nKeyLength))) {

return 1;

}

p = p->pNext;

}

这里又调用了zend_inline_hash_func函数(在zend_hash.h头文件里),这个函数说实话真没看明白,黑夜路人有篇文章有详细解释,实际就是一种hash算法,实现这么一个公式hash(i) = hash(i-1) * 33 + str[i],解释一下,php版本是这么写的:(hash << 5) + hash,左移5实际上等于成2的5次方也就是32,再加一次,就等于hash*33,最后返回的是一个相对合理的一个哈希值,这个值再和哈希表的nTableMask做与运算(看样nTableMask是个重要的掩码,其值待研究)。接着用这个运算结果作为下标去获取ht->arBuckets[nIndex],有点明白了,arBuckets里存的是相同哈希(和掩码与后的结果)值的数组,相当于将数组元素按照哈希算法归类。while循环里通过bucket p->pNext遍历查找相同arKey的元素。

至此,终于明白bucket结构里pListNext、pListLast和pNext、pLast属性的区别,前者用于顺序遍历,和元素插入先后顺序有关,后者用于按照key查找,其关联关系是根据key生成的哈希值分组,如果有相同哈希值的key,这时pNext和pLast就有作用了,再做链表关联相同哈希值的key。

回头再看zend_inline_hash_func函数,因为其返回的数值是和key的长度密切相关的,key越长散列的范围就越大,相同的哈希结果就越少,按key查找也就越快,是不是可以这样理解?

补充一下路人加了注释的hashtable和bucket结构

typedef struct _hashtable {

uint nTableSize; /* 散列表大小, Hash值的区间 */

uint nTableMask; /* 等于nTableSize -1, 用于快速定位 */

uint nNumOfElements; /* HashTable中实际元素的个数 */

ulong nNextFreeElement; /* 下个空闲可用位置的数字索引 */

Bucket *pInternalPointer; /* 内部位置指针, 会被reset, current这些遍历函数使用 */

Bucket *pListHead; /* 头元素, 用于线性遍历 */

Bucket *pListTail; /* 尾元素, 用于线性遍历 */

Bucket **arBuckets; /* 实际的存储容器 */

dtor_func_t pDestructor;/* 元素的析构函数(指针) */

zend_bool persistent;

unsigned char nApplyCount; /* 循环遍历保护 */

zend_bool bApplyProtection;

#if ZEND_DEBUG

int inconsistent;

#endif

} HashTable;

typedef struct bucket {

ulong h; /* 数字索引/hash值 */

uint nKeyLength; /* 字符索引的长度 */

void *pData; /* 数据 */

void *pDataPtr; /* 数据指针 */

struct bucket *pListNext; /* 下一个元素, 用于线性遍历 */

struct bucket *pListLast; /* 上一个元素, 用于线性遍历 */

struct bucket *pNext; /* 处于同一个拉链中的下一个元素 */

struct bucket *pLast; /* 处于同一拉链中的上一个元素 */

char arKey[1]; /* 节省内存,方便初始化的技巧 */

} Bucket;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值