本篇文章为大家展示了在PHP7项目中数组的底层实现,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。
<强> PHP数组具有的特性强>
PHP的数组是一种非常强大灵活的数据类型,在讲它的底层实现之前,先看一下PHP的数组都具有哪些特性。
可以使用数字或字符串作为数组健值
arr 美元;=,(1,=祝辞,& # 39;好# 39;,,& # 39;一个# 39;,=祝辞,& # 39;你好# 39;];
可按顺序读取数组
foreach (arr 美元;as key 美元;=祝辞,美元值){ ,echo arr美元(美元关键); }
可随机读取数组中的元素
arr 美元;=,(1,=祝辞,& # 39;好# 39;,,& # 39;一个# 39;,=祝辞,& # 39;你好# 39;,,& # 39;一个# 39;,=祝辞,& # 39;& # 39;]; echo arr美元[& # 39;一个# 39;]; echo 目前美元(arr);
数组的长度是可变的
arr 美元;=,(1,,2,,3]; 美元的arr [],=, 4; array_push (arr美元,,5);
正是基于这些特性,我们可以使用PHP中的数组轻易的实现集合,栈,列表,字典等多种数据结构。那么这些特性在底层是如何实现的呢?这就得从数据结构说起了。
<强>数据结构
强>
PHP中的数组实际上是一个有序映射。映射是一种把价值关联到钥匙的类型。
引用>
PHP数组的底层实现是散列表(也叫hashTable),散列表是根据键(关键)直接访问内存存储位置的数据结构,它的键-值之间存在一个映射函数,可以根据关键通过映射函数得到的散列值直接索引到对应的价值值,无需通过关键字比较,在理想情况下,不考虑散列冲突,散列表的查找效率是非常高的,时间复杂度是O (1)。
从源码中我们可以看到zend_array的结构如下:
typedef struct _zend_array zend_array; typedef struct  _zend_array 哈希表; struct _zend_array  { zend_refcounted_h 才能;gc; union {才能 ,,,struct { ,,,,,ZEND_ENDIAN_LOHI_4 ( ,,,,,,,,,zend_uchar ,旗帜, ,,,,,,,,,zend_uchar , nApplyCount, ,,,,,,,,,zend_uchar , nIteratorsCount, ,,,,,,,,,zend_uchar ,储备) ,,,},v; ,,,uint32_t 旗帜; ,,},u; uint32_t 才能,,,,,nTableMask;,//,哈希值计算掩码,等于nTableSize的负值(=nTableMask -nTableSize) Bucket 才能,,,,,,* arData;,,,//,存储元素数组,指向第一个桶 uint32_t 才能,,,,,nNumUsed;,,//,已用桶数(含失效的,桶) uint32_t 才能,,,,,nNumOfElements;,//,哈希表有效元素数 uint32_t 才能,,,,,nTableSize;,,,//,哈希表总大小,为2的n次方(包括无效的元素) uint32_t 才能,,,,,nInternalPointer;,//,内部指针,用于遍历 zend_long 才能,,,,,nNextFreeElement;,//,下一个可用的数值索引,如:加勒比海盗[],=,1;arr [“a"],=, 2, arr[],=, 3;,则nNextFreeElement =, 2; dtor_func_t 才能,,,,pDestructor; };该结构中的桶即储存元素的数组,arData指向数组的起始位置,使用映射函数对关键值进行映射后可以得到偏移值,通过内存起始位置+偏移值即可在散列表中进行寻址操作。
斗的数据结构如下:
typedef struct _Bucket { zval 才能,,,,,,,val,,//,存储的具体,价值,这里是一个,zval,而不是一个指针 zend_ulong 才能,,,,h,,,//,数字,key 或字符串,key 的哈希值。用于查找时,key 的比较,, zend_string 才能,,,*键,,//,当,key 值为字符串时,指向该字符串对应的,zend_string(使用数字索引时该值为,NULL),用于查找时,key 的比较 },桶;到这里有个问题出现了:存储在散列表里的元素是无序的,PHP数组如何做到按顺序读取的呢?
答案是中间映射表,为了实现散列表的有序性,PHP为其增加了一张中间映射表,该表是一个大小与斗相同的数组,数组中储存整形数据,用于保存元素实际储存的价值在Bucekt中的下标.Bucekt中的数据是有序的,而中间映射表中的数据是无序的。
而通过映射函数映射后的散列值要在中间映射表的区间内,这就对映射函数提出了要求。
<强>映射函数强>
PHP7数组采用的映射方式:
在PHP7项目中数组的底层实现