在PHP7项目中数组的底层实现

  介绍

本篇文章为大家展示了在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数组采用的映射方式:

在PHP7项目中数组的底层实现