PHP核心之旅-5.強大的陣列
PHP 核心之旅系列
一、陣列的內部結構
1.底層實現為散列表(HashTable,也稱作雜湊表)
2.散列表的概念:
是根據關鍵碼值(Key value)而直接進行訪問的資料結構。通過把關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做散列表。複雜度為O(1)。
檔案路徑\Zend\zend_types.h
_zend_array結構:
1 typedef struct _zend_array zend_array; 2 typedef struct _zend_array HashTable; 3 4struct _zend_array { 5 zend_refcounted_h gc; 6 union { 7 struct { 8 ZEND_ENDIAN_LOHI_4( 9 zend_uchar flags, 10 zend_uchar nApplyCount, 11 zend_uchar nIteratorsCount, 12 zend_uchar consistency)13 } v; 14 uint32_t flags; 15 } u; 16 uint32_t nTableMask; 17 Bucket *arData; 18 uint32_t nNumUsed; 19 uint32_t nNumOfElements; 20 uint32_t nTableSize; 21 uint32_t nInternalPointer; 22 zend_long nNextFreeElement;23 dtor_func_t pDestructor; 24 };
zend_array和HashTable結構相同
arData:散列表中儲存儲存元素的陣列,其記憶體是連續的,arData指向陣列的起始位置,其記憶體連續。
nTableSize:陣列的總容量,可以容納的元素數,大小是2的冪次方,最小為8
nTableMask: 對映元素的儲存位置用到,nTableSize的負數
nNumUsed: 陣列當前使用的Bucket數,刪除元素時,不會將其從陣列中移除,將這個元素的型別標為IS_UNDEF,當陣列容量超限,擴容時才會刪除。
nNumOfElements:陣列中有效元素的位置
nNextFreeElement:下一個數值的索引
pDestructor:刪除或覆蓋陣列中的某個元素時,則呼叫此函式對舊元素進行處理
u:輔助作用
Bucket結構:
1 typedef struct _Bucket { 2 zval val; 3 zend_ulong h; /* hash value (or numeric index) */ 4 zend_string *key; /* string key or NULL for numerics */ 5 } Bucket;
val: 具體的value
h: key的hash值,或者數值索引
*key: 儲存元素的key,如果元素是數值索引則為NULL
二、陣列的基本實現
雜湊函式:將元素進行hash運算後的值,對陣列大小取模之後的值(下標:0~7)分配到中間對映表
中間對映表:元素和下標的對映關係表。可以通過arData向前訪問到
元素陣列:實際儲存元素的陣列,按照下標有序儲存元素
三、陣列的初始化
\Zend\zend_hash.c
1 ZEND_API void ZEND_FASTCALL _zend_hash_init(HashTable *ht, uint32_t nSize, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC) 2 { 3 GC_REFCOUNT(ht) = 1; 4 GC_TYPE_INFO(ht) = IS_ARRAY | (persistent ? 0 : (GC_COLLECTABLE << GC_FLAGS_SHIFT)); 5 ht->u.flags = (persistent ? HASH_FLAG_PERSISTENT : 0) | HASH_FLAG_APPLY_PROTECTION | HASH_FLAG_STATIC_KEYS; 6 ht->nTableMask = HT_MIN_MASK; 7 HT_SET_DATA_ADDR(ht, &uninitialized_bucket); 8 ht->nNumUsed = 0; 9 ht->nNumOfElements = 0; 10 ht->nInternalPointer = HT_INVALID_IDX; 11 ht->nNextFreeElement = 0; 12 ht->pDestructor = pDestructor; 13 ht->nTableSize = zend_hash_check_size(nSize); 14 }
\Zend\zend_API.c
1 ZEND_API int _array_init(zval *arg, uint32_t size ZEND_FILE_LINE_DC) /* {{{ */ 2 { 3 ZVAL_NEW_ARR(arg); 4 _zend_hash_init(Z_ARRVAL_P(arg), size, ZVAL_PTR_DTOR, 0 ZEND_FILE_LINE_RELAY_CC); 5 return SUCCESS; 6 }
四、插入
插入時首先會檢查陣列已經分配儲存空間,初始化時沒有實際分配arData的記憶體,第一次插入時才會根據nTableSize的大小分配,分配完以後會把HashTable->u.flags打上HASH_FLAG_INITIALIZED掩碼,下次插入時發現已經分配了就不會再重複操作。
1 static zend_always_inline void zend_hash_check_init(HashTable *ht, int packed) 2 { 3 HT_ASSERT_RC1(ht); 4 if (UNEXPECTED(!((ht)->u.flags & HASH_FLAG_INITIALIZED))) { 5 zend_hash_real_init_ex(ht, packed); 6 } 7 } 8 9 #define CHECK_INIT(ht, packed) \ 10 zend_hash_check_init(ht, packed)
參考資料:
http://www.php-internals.com/
PHP7核心剖析
作 者:
出 處:http://www.cnblogs.com/jackson0714/
關於作者:專注於微軟平臺的專案開發。如有問題或建議,請多多賜教!
版權宣告:本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連結。
特此宣告:所有評論和私信都會在第一時間回覆。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信我
聲援博主:如果您覺得文章對您有幫助,可以點選文章右下角【推薦】一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!
相關推薦
PHP核心之旅-5.強大的陣列
PHP 核心之旅系列 一、陣列的內部結構 1.底層實現為散列表(HashTable,也稱作雜湊表) 2.散列表的概念: 是根據關鍵碼值(Key value)而直接進行訪問的資料結構。通過把關鍵碼值對映到表中一個位置來訪問記錄,以加快查詢的速度。這個對映函式叫做雜湊函式,存放記錄的陣列叫做散列表
PHP核心之旅-3.變數
PHP 核心之旅系列 一、弱型別語言 php是弱型別語言。一個變數可以表示任意資料型別。 php強大的一部分原因就是因為它是弱型別語言,但是弱型別語言也有它的缺點,使用不當也會造成很大的問題。 定義變數的時候不需要指定變數型別,也不需要初始化變數。 //定義變數 $test;
PHP核心之旅-2.SAPI中的Cli
PHP 核心之旅系列 一、SAPI是什麼? 1.1 理解SAPI (1)SAPI是PHP框架的介面層。有很多種伺服器的SAPI的實現,程式碼在sapi資料夾下。常見的介面抽象層實現有:cgi,apache2,cli,embed,fpm。 (2)各個伺服器遵循著相同的約定,每個伺服器的SAP
PHP核心之旅-6.垃圾回收機制
回收PHP 核心之旅系列 一、引用計數 只有使用引用計數的變數才需要回收。引用計數就是用來標記變數的引用次數的。 當有新的變數zval指向value時,計數器加1,當變數zval銷燬時,計數器減一。當引用計數為0時,表示此value沒有被任何變數指向,可以對value進行釋放。 下面的例子說明引用
PHP核心之旅-1.生命週期
PHP 核心之旅系列 1.SAPI介面 PHP具體應用的程式設計介面。 2.開始和結束 PHP開始執行以後會經過兩個主要的階段: 處理請求之前的開始階段和請求之後的結束階段。 1.1開始階段: 1.1.1 模組初始化階段(MINT),只進行一次。
PHP核心之旅-4.可變長度的字串
PHP 核心之旅系列 一、字串原始碼 zend_string 1 typedef struct _zend_string zend_string; //定義 zend_string變數 2 struct _zend_string { //_zend_string結構體 3
java學習之旅-5
print out 簡單 代碼 接下來 補充 移動 簡單的 直觀 說了幾個簡單的位運算符,接下來看看稍微復雜點的另外三個吧: <<: 將操作數的二進制碼整體左移指定位數,左移之後的空使用‘0’來補充。剛接觸這個所謂的“移位操作”,不一定能理解二進制碼整體移動指定
Prism V2之旅(5)
上篇介紹了WPF的Attach Behavior(附加行為)模式以及如何在prism框架中如何使用附加行為和RegionAdapter的擴充套件. 這篇來介紹Prism中的很重要的一個功能模組化. 請下載Demo 基本概念 模組化的概念類似於現在網上比較流行的Widge
PHP強化之04 - 超全域性陣列
----- 最後更新【2018-12-6】----- 一、簡介 定義:超全域性變數是在全部作用域中始終可用的內建變數。 在PHP中超全域性變數一共有9種,它們分別是:$GLOBALS、$_SERVER、$_GET、$_POST、$_FILES、$_COOKIE、$_SESSI
Html5學習之旅(5)嵌入元素 progress meter embed audio video
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="utf-8">
Linux下PHP開發之旅-2.開發環境相關設定探索
一.預設目錄在哪兒? 開始時面對該xampp整合開發環境的相關配置有點不知所錯,於是便先想著找httpd.conf,通過該檔案,對該整合環境的配置檔案關係有了大致瞭解,具體操作如下; cd /opt/lampp/etc vi httpd.conf 預設ServerName
Linux下PHP開發之旅-1.開發環境搭建
一.下載相關安裝包 從官網:https://www.apachefriends.org/download.html 下載對應版本的安裝包,由於學的版本為5.5,選擇5.6版本安裝包 二.執行安裝 由於下載的檔案直接就是xampp-linux-x64-5.6.39-0-i
TOMCAT核心之旅--一個簡單的WEB伺服器--學習心得(一)
TOMCAT核心之旅–一個簡單的WEB伺服器–學習心得(一) 標籤(空格分隔): web伺服器 一、學習背景 本人是一名大三學生,開始以java學習為主,後來學習了javaWEB,瞭解到了TOMCAT伺服器,很好奇其內部是如何實現的,其與瀏覽器
PHp學習之路二(陣列練習)
有關陣列的練習,,php不同於java和c++他是弱型別的語言,php陣列卻很強大····它既有java中陣列的特性 又有集合的用途。<?php //遍歷陣列, 方法一:列印變數 $a=array("Hello", "World!", ); var_d
一次失敗的PHP擴展開發之旅
erro 一個 google 討論 c++開發 .com center goroutine text 一次失敗的PHP擴展開發之旅 By warezhou 2014.11.19 緣起 經過不斷的持續叠代。我們部門的協程版網絡框架(CoSvrFrame)最終出爐了!
單片機小白的啟程之旅(5)
芯片 常用 是把 半導體 就是 pan int IT size 外設與內部外設 外設 peripheral,外部設備,單片機中的模塊,例如單片機中的串口控制器和I2C控制器。 單片機早期的功能較弱,外部擴展專用芯片與單片機結合(做到一塊電路板上用導線連接)工作,而這個外
PHP內核之旅-4.可變長度的字符串
mage nbsp 字符串結束 val ffffff 分享 not span typedef PHP 內核之旅系列 PHP內核之旅-1.生命周期 PHP內核之旅-2.SAPI中的Cli PHP內核之旅-3.變量 PHP內核之旅-4.字符串 一、字符串源碼
記一次修改php.ini不生效的踩坑之旅
前言 想給公司的測試環境裝一個xdebug,按照以往的方式(之前已經裝過很多次了),編譯安裝了xdebug,然後修改php.ini,將xdebug擴充套件加進去,可是,不論怎麼改,都不生效,xdebug就是沒有。 首先,我想到的是xdebug版本不對,由於之前有過這種經驗,xdebug安裝了
在Docker中執行PHP專案的探索之旅
Docker出現後,容器技術在網際網路領域得到了空前的普及,無論是大公司還是屌絲創業公司的碼農基本上都會在各種技術社群或者各種演講會議上了解到過相關技術,我們作為一家屌絲創業公司也不例外,去年對Docker做了一番瞭解,並在年前測試了一些方案,今天在這裡總結一下遇到的各種坑以及踩坑過程中的一
PHP之旅
記錄一下: 我Android的,但覺得APP沒有個管理後臺不行呀,老是用第三方的後臺也不是辦法,比如bmob,雖然開發者使用起來很方便,直接用他寫好的方法,但過度的包裝,使得