目錄
前言
正文
ZVALUE_VALUE VALUE
ZEND_UINT REFCOUNT__GC
ZEND_UCHAR TYPE
ZEND_UCHAR IS_REF__GC
PHP7中的zval
总结
参考
首頁 後端開發 php教程 PHP內核之zval

PHP內核之zval

Apr 19, 2018 am 09:26 AM
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。

总结


  1. zval 是一种 C 语言实现的数据结构,功能是作为 PHP 变量的容器;

  2. 它保存了变量的各种信息(如类型和值),并为其他功能(如垃圾回收)提供支持;

  3. 在不同的 PHP 版本中,它的结构不同。PHP7 的 zval 占 16 个字节,PHP5 的要占 24 个字节。

参考


PHP内核探索之变量(1)变量的容器-Zval
PHP垃圾回收深入理解
深入理解PHP7之zval

相关推荐:

PHP内核之探究内存管理与缓存机制

PHP内核分析-Zend虚拟机详解

以上是PHP內核之zval的詳細內容。更多資訊請關注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 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++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教學
1664
14
CakePHP 教程
1423
52
Laravel 教程
1318
25
PHP教程
1269
29
C# 教程
1248
24
在PHP API中說明JSON Web令牌(JWT)及其用例。 在PHP API中說明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

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

解釋PHP中的晚期靜態綁定(靜態::)。 解釋PHP中的晚期靜態綁定(靜態::)。 Apr 03, 2025 am 12:04 AM

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

什麼是PHP魔術方法(__ -construct,__destruct,__call,__get,__ set等)並提供用例? 什麼是PHP魔術方法(__ -construct,__destruct,__call,__get,__ set等)並提供用例? Apr 03, 2025 am 12:03 AM

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

PHP和Python:比較兩種流行的編程語言 PHP和Python:比較兩種流行的編程語言 Apr 14, 2025 am 12:13 AM

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

PHP行動:現實世界中的示例和應用程序 PHP行動:現實世界中的示例和應用程序 Apr 14, 2025 am 12:19 AM

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

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

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

PHP的持久相關性:它還活著嗎? PHP的持久相關性:它還活著嗎? Apr 14, 2025 am 12:12 AM

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

說明匹配表達式(PHP 8)及其與開關的不同。 說明匹配表達式(PHP 8)及其與開關的不同。 Apr 06, 2025 am 12:03 AM

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

See all articles