PHP內核之zval
這篇文章主要介紹的內容是關於PHP核心之zval,有著一定的參考價值,現在分享給大家,有需要的朋友可以參考一下
原文地址
作者:Twei 主頁
前言
之前面試的時候面試官問過php中變數是如何實現的,遺憾的是只答道了大概是用結構體實現的。這篇文章是谷歌之後覺得總結 的比較到位的,故轉載進而學習之。
正文
PHP中的資料型別
#相對於C、 C 、 Java等其他程式語言,PHP 是一個弱型別的語言,表示當我們要使用一個變數時,不需要去宣告它的型別。這個特性為我們帶來了許多便利,同時有時也會帶來一些陷阱。那麼,PHP 是真的沒有資料型這個說法嗎?
當然不是。在 PHP 官方文件中將 PHP 中的變數劃分為三類:標量類型、複雜型別和特殊型別。標量類型包括布林型(bool)、整數型(int)、浮點型(float)和字串(string);複雜型別包括陣列(array)和物件(object);特殊型別包括NULL 和資源(resource) 。所以說 PHP 的變數細分的話,有 8 種資料型別。
總所周知,PHP 的底層是用 C 語言實現的。我們的 PHP 腳本會經過 Zend 引擎解析為 C 程式碼再執行。那麼,一個 PHP 的變量,在 C 語言上是怎麼表示的呢?它最終會被解析成什麼樣子呢?
答案就是 zval。不管什麼類型的 PHP 變量,在 PHP 原始碼中統一用一個叫做 zval 的結構表示。 zval 可以看做是 PHP 變數在 C 程式碼中的容器,它儲存了這個變數的值、型別等相關資訊。
那我們就來看看 zval 的基本結構(需要一點 C 語言的基本知識)。
zval的基本結構
在PHP 原始碼中zval 這個結構是一個名叫_zval_struct
的結構體(struct) ,具體定義在原始碼的Zend/zend.h
檔案中,下面是相關程式碼的摘錄:
struct _zval_struct { zvalue_value value; /* value */ zend_uint refcount__gc; /* value of ref count */ zend_uchar type; /* active type */ zend_uchar is_ref__gc; /* if it is a ref variable */ }; typedef struct _zval_struct zval;
也就是說,在PHP 的原始碼中,就用這一個結構體表示PHP 中各種類型的變量,並且還可以實現其他的一些功能,例如垃圾回收(GC:Grabage Collection)。
可以看到它由 4 個欄位構成,分別表示這個變數的某個資訊。
ZVALUE_VALUE VALUE
value 用來表示變數的實際值,具體來說它是一個zvalue_value 的聯合體(union):
typedef union _zvalue_value { long lval; /* long value */ double dval; /* double value */ struct { /* string */ char *val; int len; } str; HashTable *ht; /* hash table value,used for array */ zend_object_value obj; /* object */} zvalue_value;
可以看到_zvalue_value 中只有5 個字段,但是PHP 中有8 種資料類型,那麼如何用5 個字段表示8 種類型呢?
這算是 PHP 設計比較巧妙的地方,它透過重複使用欄位達到了減少欄位的目的。例如,在PHP 內部布林型、整數及資源(只要儲存資源的識別碼即可)都是透過lval 欄位儲存的;dval 用於儲存浮點型;str 儲存字串;ht 儲存陣列(注意PHP 中的陣列其實是雜湊表);而obj 儲存物件類型;如果所有欄位全部置為0 或NULL則表示PHP 中的NULL,這樣就達到了用5 個欄位儲存8 種類型的值。
ZEND_UINT REFCOUNT__GC
從它的字尾 gc 可以看到,這個欄位是和垃圾回收相關的。
它實際上是一個計數器,用來保存有多少變數指向該zval。在變數生成時,置為1,也就是 refcount = 1。
對變數進行不同的操作會改變它的值。典型的賦值運算如
b 會使 refcount 加 1,而 unset() 運算會對應的減 1。
透過判斷它的值可以進行垃圾回收。在 PHP5.3 之前,使用引用計數的機制來實作 GC:如果一個 zval 的 refcount 減為 0,那麼 Zend 引擎會認為沒有任何變數指向該 zval,就會釋放該 zval 所佔的記憶體空間。但僅僅使用引用計數機制無法釋放掉循環引用的 zval,這是就會導致記憶體洩漏(Memory Leak)。
在5.3 以前,這個欄位的名字還叫做refcount,5.3 以後,在引入新的垃圾回收演算法來對付循環引用,作者加入了大量的巨集來操作refcount,為了能讓錯誤更快的顯現,所以改名為refcount__gc, 迫使大家都使用巨集來操作refcount。
類似的, 還有第四個欄位 is_ref, 這個值表示了 PHP 中的一個類型是否是引用。
想了解 PHP 的垃圾回收機制,可以參考這篇部落格:PHP的垃圾回收機制
註:變量,也可以稱為符號,symbol。所有的符號都存在符號表(symbol table)中, 不同的作用域使用不同的符號表,關於這一點,這篇博客進行了講解。
ZEND_UCHAR TYPE
这个字段用于表明变量属于 PHP 8 种类型的哪种。在 zend 内部,这些类型对应于下面的宏(代码位置 phpsrc/Zend/zend.h):
#define IS_NULL 0#define IS_LONG 1#define IS_DOUBLE 2#define IS_BOOL 3#define IS_ARRAY 4#define IS_OBJECT 5#define IS_STRING 6#define IS_RESOURCE 7#define IS_CONSTANT 8#define IS_CONSTANT_ARRAY 9#define IS_CALLABLE 10
ZEND_UCHAR IS_REF__GC
这个字段用于标记变量是否是引用变量。对于普通的变量,该值为 0,而对于引用型的变量,该值为 1。这个变量会影响 zval 的共享、分离等。它也和 PHP 的垃圾回收有关。
PHP7中的zval
上述的 zval 结构,随着时间的发展,暴露出许多问题,例如占用空间大(24 字节)、不支持拓展、 对象和引用效率差等,所以在 PHP7 的时候,对 zval 进行了较大的改变,现在它的结构是这样的:
struct _zval_struct { union { zend_long lval; /* long value */ double dval; /* double value */ zend_refcounted *counted; zend_string *str; zend_array *arr; zend_object *obj; zend_resource *res; zend_reference *ref; zend_ast_ref *ast; zval *zv; void *ptr; zend_class_entry *ce; zend_function *func; struct { uint32_t w1; uint32_t w2; } ww; } value; union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar type, /* active type */ zend_uchar type_flags, zend_uchar const_flags, zend_uchar reserved) /* call info for EX(This) */ } v; uint32_t type_info; } u1; union { uint32_t var_flags; uint32_t next; /* hash collision chain */ uint32_t cache_slot; /* literal cache slot */ uint32_t lineno; /* line number (for ast nodes) */ uint32_t num_args; /* arguments number for EX(This) */ uint32_t fe_pos; /* foreach position */ uint32_t fe_iter_idx; /* foreach iterator index */ } u2; };
虽然看起来变得好大,但其实仔细看,它的字段都是联合体,这个新的 zval 在 64 位环境下,只需要 16 个字节(2 个指针 size)。PHP7 中的 zval,已经变成了一个值指针,它要么保存着原始值,要么保存着指向一个保存原始值的指针。
这部分内容来自鸟哥的GitHub。
总结
zval 是一种 C 语言实现的数据结构,功能是作为 PHP 变量的容器;
它保存了变量的各种信息(如类型和值),并为其他功能(如垃圾回收)提供支持;
在不同的 PHP 版本中,它的结构不同。PHP7 的 zval 占 16 个字节,PHP5 的要占 24 个字节。
参考
PHP内核探索之变量(1)变量的容器-Zval
PHP垃圾回收深入理解
深入理解PHP7之zval
相关推荐:
以上是PHP內核之zval的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

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

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

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

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

靜態綁定(static::)在PHP中實現晚期靜態綁定(LSB),允許在靜態上下文中引用調用類而非定義類。 1)解析過程在運行時進行,2)在繼承關係中向上查找調用類,3)可能帶來性能開銷。

PHP的魔法方法有哪些? PHP的魔法方法包括:1.\_\_construct,用於初始化對象;2.\_\_destruct,用於清理資源;3.\_\_call,處理不存在的方法調用;4.\_\_get,實現動態屬性訪問;5.\_\_set,實現動態屬性設置。這些方法在特定情況下自動調用,提升代碼的靈活性和效率。

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP仍然具有活力,其在現代編程領域中依然佔據重要地位。 1)PHP的簡單易學和強大社區支持使其在Web開發中廣泛應用;2)其靈活性和穩定性使其在處理Web表單、數據庫操作和文件處理等方面表現出色;3)PHP不斷進化和優化,適用於初學者和經驗豐富的開發者。

在PHP8 中,match表達式是一種新的控制結構,用於根據表達式的值返回不同的結果。 1)它類似於switch語句,但返回值而非執行語句塊。 2)match表達式使用嚴格比較(===),提升了安全性。 3)它避免了switch語句中可能的break遺漏問題,增強了代碼的簡潔性和可讀性。
