數組是PHPer最經常使用的數據類型,同時php容易上手也得益於其強大的數組,可是數組在php中是如何實現的呢?php
首先,咱們仍是先了解下相關的數據結構,爲下面的內容打好基礎segmentfault
哈希表
,顧名思義,即將不一樣的關鍵字映射到不一樣單元的一種數據結構。而將不一樣關鍵字映射到不一樣單元的方法就叫作哈希函數
數組
理想狀況下,通過哈希函數處理,關鍵字和單元是會進行一一對應的;可是若是關鍵字值足夠多的狀況下,就容易出現多個關鍵字映射到同一單元的狀況,即出現哈希衝突
網絡
哈希衝突的解決方案,要麼使用連接法
,要麼使用開放尋址法
數據結構
連接法
即當不一樣的關鍵字映射到同一單元時,在同一單元內使用鏈表來保存這些關鍵字函數
開放尋址法
即當插入數據時,若是發現關鍵字被映射到的單元存在數據了,說明發生了衝突,就繼續尋找下一個單元,直到找到可用單元爲止性能
而由於開放尋址法方案屬於佔用其餘關鍵字映射單元的位置,因此後續的關鍵字更容易出現哈希衝突,所以容易出現性能降低優化
既然上面提到了鏈表,這裏咱們簡單聊一下鏈表的基礎知識。鏈表分爲不少種類型,經常使用的數據結構包括:隊列,棧,雙向鏈表等ui
鏈表,就是由不一樣的鏈表節點組成的一種數據結構。鏈表節點通常由元素
+指向下一節點的指針
組成。而雙向鏈表,顧名思義,則是由指向上一節點的指針
+元素
+指向下一節點的指針
組成spa
對於數據結構的內容,咱們不過多展開,咱們以後會有專門的內容去詳細介紹數據結構
php解決哈希衝突的方式是使用了連接法,因此php數組是由哈希表
+鏈表
實現,準確來講,是由哈希表
+雙向鏈表
實現
HashTable結構體主要用來存放哈希表的基本信息
typedef struct _hashtable { uint nTableSize; // hash Bucket的大小,即哈希表的容量,最小爲8,以2x增加。 uint nTableMask; // nTableSize-1 , 索引取值的優化 uint nNumOfElements; // hash Bucket中當前存在的元素個數,count()函數會直接返回此值 ulong nNextFreeElement; // 下一個可以使用的數字鍵值 Bucket *pInternalPointer; // 當前遍歷的指針(foreach比for快的緣由之一) Bucket *pListHead; // 存儲整個哈希表的頭元素指針 Bucket *pListTail; // 存儲整個哈希表的尾元素指針 Bucket **arBuckets; // 存儲hash數組 dtor_func_t pDestructor; // 在刪除元素時執行的回調函數,用於資源的釋放 zend_bool persistent; //指出了Bucket內存分配的方式。若是persisient爲TRUE,則使用操做系統自己的內存分配函數爲Bucket分配內存,不然使用PHP的內存分配函數。 unsigned char nApplyCount; // 標記當前hash Bucket被遞歸訪問的次數(防止屢次遞歸) zend_bool bApplyProtection;// 標記當前hash桶容許不容許屢次訪問,不容許時,最多隻能遞歸3次 #if ZEND_DEBUG int inconsistent; #endif } HashTable;
Bucket結構體則用於保存數據的具體內容
typedef struct bucket { ulong h; // 對char *key進行hash後的值,或者是用戶指定的數字索引值 uint nKeyLength; // hash關鍵字的長度,若是數組索引爲數字,此值爲0 void *pData; // 指向value,通常是用戶數據的副本,若是是指針數據,則指向pDataPtr void *pDataPtr; // 若是是指針數據,此值會指向真正的value,同時上面pData會指向此值 struct bucket *pListNext; // 指向整個哈希表的該單元的下一個元素 struct bucket *pListLast; // 指向整個哈希表的該單元的上一個元素 struct bucket *pNext; // 指向因爲哈希衝突致使存放在同一個單元的鏈表中的下一個元素 struct bucket *pLast; // 指向因爲哈希衝突致使存放在同一個單元的鏈表中的上一個元素 // 保存當前值所對於的key字符串,這個字段只能定義在最後,實現變長結構體 char arKey[1]; } Bucket;
其中Bucket結構體內有指向用戶數據的pData元素,實際上是指向了以前咱們介紹的變量zval結構體,這也是爲何當建立數組時,會出現數組元素+1的變量容器。不瞭解變量底層相關知識的,請查看我以前的文章:
哈希表內部結構關係圖
注:圖片來源於網絡
從上圖咱們能夠看出,Bucket在存放數據的時候,若是存在哈希衝突,則將多個關鍵字映射到鏈表中,由此組成了雙向鏈表
今天,咱們以數組做爲切入點,簡單瞭解了下基本的數據結構:哈希表和鏈表;而且瞭解了數組的底層實現,即哈希表
+雙向鏈表
。其實哈希表做爲php中最重要的數據結構,用處很廣。變量的符號表,函數列表等都是用哈希表來存儲的,感興趣的同窗能夠看我以前的文章來了解相關知識