首頁 後端開發 PHP8 解析PHP8底層內核源碼-陣列(二)

解析PHP8底層內核源碼-陣列(二)

Jun 10, 2021 pm 02:50 PM
php8 陣列

這篇文章為大家介紹《解析PHP8底層核心原始碼-陣列(二)》。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

相關文章推薦:《解析PHP8底層核心源碼-陣列(一)》《解析PHP8底層核心原始碼-陣列(三)》《解析PHP8底層核心原始碼-陣列(四)

zend_array 在 PHP中被分成兩種

1.packed array
2.hash array

#
在上文中 补齐了zend_array的 所有值的 注释
登入後複製

其實原始碼裡順序和我上面的稍微不一樣我覺得我上面的順序理解起來更合理

//源码里的代码
typedef struct _zend_array HashTable;
struct _zend_array {
zend_refcounted_h gc;
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar    flags,
zend_uchar    _unused,
zend_uchar    nIteratorsCount,
zend_uchar    _unused2)
} v;
uint32_t flags;
} u;
uint32_t          nTableMask;
Bucket           *arData;
uint32_t          nNumUsed;
uint32_t          nNumOfElements;
uint32_t          nTableSize;
uint32_t          nInternalPointer;
zend_long         nNextFreeElement;
dtor_func_t       pDestructor;
};
//我调换下顺序后的代码
struct _zend_array {
zend_refcounted_h gc; 
 ///  gc  占用8个字节 用于引用计数和  字符串类型的记录
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar    flags,
// flags   8位的无符号字符, 最大值为255   标记HashTable用 PHP8 中有6个值
zend_uchar    _unused,
zend_uchar    nIteratorsCount,
//迭代器计数。foreach语句会在全局变量EG中创建一个迭代器,
//迭代器包含正在遍历的HashTable和游标信息。
//nIteratorsCount记录了当前runtime正在迭代当前HashTable的迭代器的数量。
zend_uchar    _unused2)
} v;
  //这里有点不一样 看陈雷大佬书中 v结构体还包括 u.v.nApplyCount和u.v.consistency
uint32_t flags;
             //
} u;
// u是是一个联合体。占用4个字节。
//可以存储一个uint32_t类型的flags,也可以存储由4个unsigned char组成的结构体v,
//这里的宏ZEND_ENDIAN_LOHI_4是为了兼容不同操作系统的大小端,可以忽略。
Bucket           *arData;
//HashTable中存储数据的单元的指针。
//  用来存储key和value以及辅助信息的容器。
uint32_t          nTableSize;
//    HashTable的大小。表示arData指向的bucket数组的大小,即所有bucket的数量。
//该字段取值始终是2n,最小值是8,最大值在64位系统中是0x80000000(2的31次幂)。
uint32_t          nNumUsed;
//指所有已使用bucket的数量,包括有效bucket和无效bucket的数量
uint32_t          nNumOfElements;
//有效bucket的数量。该值总是小于或等于nNumUsed
uint32_t          nTableMask;
//索引大小。一般值为  -nTableSize。
uint32_t          nInternalPointer;
//全局默认游标。reset/key/current/next/prev等宏 和操作都会用到
zend_long         nNextFreeElement;
//下一个插入的元素的key的下标  
//比如  当$a[] = 1  nNextFreeElement =1  
dtor_func_t       pDestructor;
//指向一个函数   typedef void (*dtor_func_t)(zval *pDest);
//可以看出是pDest是zval结构指针二级指针,
//为什么会是二级指针,因为c语言函数传递都是值传递,要改变指针值只能将指针地址传入
//当bucket元素被更新或者被删除时,会对bucket的value调用该函数,
//如果value是引用计数的类型,那么会对value引用计数减1,进而引发可能的gc。
};
登入後複製

用understand 工具產生的成員變數圖如下

解析PHP8底層內核源碼-陣列(二)

展開全部後如下

解析PHP8底層內核源碼-陣列(二)

zend_array 結構體member

可以看出其實核心就是z_val   zend_string zend_refcounted_h Bucket層層相扣

其中Bucket 儲存陣列的關鍵資訊

typedef struct _Bucket {
zval              val;   //数组的值 ( 复习下 zval只有16个字节)
zend_ulong         h;     // key的 h  值
zend_string      *key;      //当数组为 hash_array时候 会用到 也就是 key的值  
} Bucket;
登入後複製

#不管陣列類型是packed_array 還是hash_array  最後都會儲存在Bucket中

當 key全是數字key 且 key依插入順序遞增的時候陣列型別為packed_array

packed array的特性

  1.  不需要索引陣列 
  2.  無法使用key  
  3. 不含key的陣列h 值直接等於bucket中空間的排序值從0開始
  4. key-value對的陣列 h 值等於key的內容

其中第三條和第四條你可以理解為PHP中數組如果不寫key 那麼就默認key就從0開始依次排序

#
$a =array(1,2,3);  // packed array
$b =array(1=>'a',3=>'b',5=>'c'); //packed array
登入後複製
解析PHP8底層內核源碼-陣列(二)

bucket 陣列前會有索引陣列

當為packed array 時 索引陣列得大小一直為2  因為用不到它

上面當$a 對應的 zend_array裡的內容為

解析PHP8底層內核源碼-陣列(二)
$a 的zend_array

#nTableSize;    表示arData所指向的bucket陣列的大小,即所有bucket的數量。 =陣列的總大小

nNumUsed;        指所有使用bucket的數量,包括有效bucket和無效bucket的數量

        使用 

nNumOfElements;      有效bucket的數量。

所以 nNumOfElements nNumUsed =nTableSize

nTableMask;   索引大小。因為packed array 沒有用到索引所以永遠為-2

nNextFreeElement;   下一個插入的元素的key的下標

packed array  利用了bucket數組的連續性特點,對於某些只有數字key的場景進行的最佳化。由於不再需要索引數組,從記憶體空間上節省了(nTableSize-2 )* sizeof(uint32_t) 個位元組。另外,由於存取bucket是直接操作bucket數組,因此在效能上也有所提升。

如果未滿足packed array 的條件 在PHP中陣列用hash_array表示

所有key 值不是數字的都用hash_array 表示

$c =array('x'=>1,'y'=>2,'z'=>3,'a'=>0);
登入後複製

上面的$c 會被用hash_array  表示

bucket如下

解析PHP8底層內核源碼-陣列(二)
#$c 的bucket

zend_array如下

解析PHP8底層內核源碼-陣列(二)
$c 的zend_array

#nTableSize;    表示arData所指向的bucket陣列的大小,即所有bucket的數量。 =8

nNumUsed;        指所有使用bucket的數量,包括有效bucket和無效bucket的數量=4

        

nNumOfElements;      有效bucket的數量。 =4

所以 nNumOfElements nNumUsed =nTableSize

#nTableMask;   索引大小。 -8

nNextFreeElement;   下一個插入的元素的key的下標 hash_array 用不到永遠為0

▏本文經原作者PHP崔雪峰同意,發佈在php中文網,原文網址:https://zhuanlan.zhihu.com/p/358354087

以上是解析PHP8底層內核源碼-陣列(二)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

<🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系統,解釋
3 週前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1666
14
CakePHP 教程
1425
52
Laravel 教程
1325
25
PHP教程
1273
29
C# 教程
1252
24
如何使用 foreach 迴圈移除 PHP 陣列中的重複元素? 如何使用 foreach 迴圈移除 PHP 陣列中的重複元素? Apr 27, 2024 am 11:33 AM

使用foreach循環移除PHP數組中重複元素的方法如下:遍歷數組,若元素已存在且當前位置不是第一個出現的位置,則刪除它。舉例而言,若資料庫查詢結果有重複記錄,可使用此方法移除,得到不含重複記錄的結果。

PHP 陣列鍵值翻轉:不同方法的效能比較分析 PHP 陣列鍵值翻轉:不同方法的效能比較分析 May 03, 2024 pm 09:03 PM

PHP數組鍵值翻轉方法效能比較顯示:array_flip()函數在大型數組(超過100萬個元素)下比for迴圈效能更優,耗時更短。手動翻轉鍵值的for迴圈方法耗時相對較長。

PHP數組深度複製的藝術:使用不同方法完美複製 PHP數組深度複製的藝術:使用不同方法完美複製 May 01, 2024 pm 12:30 PM

PHP中深度複製數組的方法包括:使用json_decode和json_encode進行JSON編碼和解碼。使用array_map和clone進行深度複製鍵和值的副本。使用serialize和unserialize進行序列化和反序列化。

PHP數組多維排序實戰:從簡單到複雜場景 PHP數組多維排序實戰:從簡單到複雜場景 Apr 29, 2024 pm 09:12 PM

多維數組排序可分為單列排序和嵌套排序。單列排序可使用array_multisort()函數依列排序;巢狀排序需要遞歸函數遍歷陣列並排序。實戰案例包括按產品名稱排序和按銷售量和價格複合排序。

PHP 數組分組函數在資料整理的應用 PHP 數組分組函數在資料整理的應用 May 04, 2024 pm 01:03 PM

PHP的array_group_by函數可依鍵或閉包函數將陣列中的元素分組,傳回關聯數組,其中鍵為組名,值是屬於該組的元素數組。

深度複製PHP數組的最佳實踐:探索高效的方法 深度複製PHP數組的最佳實踐:探索高效的方法 Apr 30, 2024 pm 03:42 PM

在PHP中執行陣列深度複製的最佳實踐是:使用json_decode(json_encode($arr))將陣列轉換為JSON字串,然後再轉換回陣列。使用unserialize(serialize($arr))將陣列序列化為字串,然後將其反序列化為新陣列。使用RecursiveIteratorIterator迭代器對多維數組進行遞歸遍歷。

探索 PHP 陣列去重演算法的複雜度 探索 PHP 陣列去重演算法的複雜度 Apr 28, 2024 pm 05:54 PM

PHP陣列去重演算法的複雜度:array_unique():O(n)array_flip()+array_keys():O(n)foreach迴圈:O(n^2)

PHP 陣列分組函數在尋找重複元素中的作用 PHP 陣列分組函數在尋找重複元素中的作用 May 05, 2024 am 09:21 AM

PHP的array_group()函數可用來按指定鍵對陣列進行分組,以尋找重複元素。函數透過以下步驟運作:使用key_callback指定分組鍵。可選地使用value_callback確定分組值。對分組元素進行計數並識別重複項。因此,array_group()函數對於尋找和處理重複元素非常有用。

See all articles