数组key和value的限制条件
1 <?php 2 $arr = array( 3 1 => 'a', 4 "1" => "b", 5 1.5 => "c", 6 true => "d" 7 ); 8 var_dump($arr); 9 10 $arr = array( 11 "foo" => "bar", 12 "bar" => "foo", 13 100 => -100, 14 -100 => 100 15 ); 16 var_dump($arr);
运行结果:
array (size=1)
1 => string 'd' (length=1)
array (size=4)
'foo' => string 'bar' (length=3)
'bar' => string 'foo' (length=3)
100 => int -100
-100 => int 100
- ·key 可以是integer或者string
- ·value 可以使任意类型。
key会有如下的强制转换:
- ·包含有合法整形值得字符串会被转换为整型
- ·浮点数和布尔值也会被转换为整型
- ·键名null实际会被存储为“”
- ·数组和对象不能被用为键名
- ·相同键名,之前会被覆盖
数组内部实现:
- ·实现数组使用了两个数据结构,一个是HashTable,另一个是bucket。
- ·HashTable结构体用于保存整个数组需要的基本信息。
- ·Bucket结构体用于保存具体的数据内容
HashTable是什么?
哈希表,是根据关键字(key value)而直接访问在内存存储位置的数据结构。也就是说,它通过把键值通过一个函数的计算,映射到保重一个位置来访问记录,这加快了查找速度。使得普通的查找和插入、杀出操作都可以在O(1)的时间内完成。这个映射函数称作哈希函数,存放记录的数组称作哈希表。
HashTable结构体的表示:
1 typedef struct _hashtable { 2 uint nTableSize; //hash Bucket的大小,最小为8,以二倍增长 3 uint nTableMask; //nTableSize-1,索引取值的优化,193491849 & 127 4 uint nNumOfElements; //hash Bucket中当前存在的元素个数,count()函数会直接返回此值 5 ulong nNextFreeElement; //下一个数字索引的位置 6 Bucket *pInternalPointer; //当前遍历的指针,foreach比for快的原因之一,reset,current遍历函数使用 7 Bucket *pListHead; //存储数组头元素指针 8 Bucket *pListTail; //存储数组尾元素指针 9 Bucket **arBuckets; //存储hash数组,实际的存储容器 10 dtor_func_t pDestructor; 11 zend_bool persistent; 12 unsigned char nApplyCount; //标记当前hash bucket被递归访问的次数(防止多次递归) 13 zend_bool bApplyProtection; 14 #if ZEND_DEBUG 15 int inconsistent; 16 #endif 17 } HashTable;
Bucket结构体:
1 typedef struct bucket { 2 ulong h; //对char *key进行hash后的值,或者使用户指定的数字索引值 3 uint nKeyLength; //hash关键字的长度,如果数组索引为数字,此值为0 4 void *pData; //指向value,一般是用户数据的副本,如果是指针数据,则指向pDataPtr 5 void *pDataPtr; //如果是指针数据,此值会指向真正的value,同时上面pData会指向此值 6 struct bucket *pListNext; //整个hash表的下一个元素 7 struct bucket *pListLast; //整个hash表表元素的上一个元素 8 struct bucket *pNext; //存放在同一个hash Bucket内的下一个元素 9 struct bucket *pLast; //同一个hash bucket的上一个元素 10 const char *arKey; //保存当前key所对应的字符串值 11 } Bucket;
总结成一张图,如下: