首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

深入理解 PHP 內核(五):變數結構 zval 與弱類型實現原理

     編輯:PHP 相關知識

深入理解 PHP 內核(五):變數結構 zval 與弱類型實現原理

PHP 是弱類型語言,但底層由 C 實現(強類型)。所有 PHP 變數在內核中統一使用 zval 結構體存儲,包含值、類型、引用計數、是否引用四大欄位。本文詳細解析 zval、zvalue_value 結構,以及標量、陣列、物件、資源等類型的存儲方式。

一、zval 結構體定義(PHP 5.3+)

// Zend/zend.h
typedef struct _zval_struct zval;

struct _zval_struct {
    zvalue_value value;     // 變數實際值(聯合體)
    zend_uint    refcount__gc; // 引用計數(GC)
    zend_uchar   type;       // 類型標識
    zend_uchar   is_ref__gc; // 是否為引用
};

欄位說明:

  • value:聯合體 zvalue_value,根據 type 解釋不同欄位。
  • refcount__gc:引用計數,初始為 1。PHP 5.3 引入 GC 後改名(舊版為 refcount)。
  • type:IS_NULL、IS_BOOL、IS_LONG、IS_DOUBLE、IS_STRING、IS_ARRAY、IS_OBJECT、IS_RESOURCE、IS_CONSTANT、IS_CONSTANT_ARRAY。
  • is_ref__gc:是否為引用(&),初始 0。

二、zvalue_value 聯合體

typedef union _zvalue_value {
    long         lval;      // 整數、布爾
    double       dval;      // 浮點數
    struct {
        char *val;          // 字串指標
        int   len;          // 字串長度
    } str;
    HashTable *ht;          // 陣列
    zend_object_value obj;  // 物件
} zvalue_value;

三、各類型存儲詳解

1. 標量類型(整數、布爾、浮點數、NULL)

  • 整數/布爾:存入 value.lval,type = IS_LONG/IS_BOOL。宏 ZVAL_LONG(z, 123)、ZVAL_BOOL(z, 1)。
  • 浮點數:存入 value.dval,type = IS_DOUBLE。宏 ZVAL_DOUBLE(z, 3.14)。
  • NULL:不佔用 value,僅設 type = IS_NULL。宏 ZVAL_NULL(z)。

2. 資源類型

本質是整數句柄,存入 value.lval,type = IS_RESOURCE。宏 ZVAL_RESOURCE(z, handle)。實際資源結構體存放在全局資源表 EG(regular_list) 中。

3. 字串

使用 value.str 結構:val 指向字串記憶體,len 記錄長度(不含結束符)。為何存長度? 字串操作極高頻,預存長度避免每次 strlen() 掃描,空間換時間。

4. 陣列

value.ht 指向 HashTable。PHP 陣列底層是有序哈希表,支援整數/字串鍵混合、遍歷順序即插入順序。核心結構:Bucket(鍵值節點)+ HashTable(桶陣列+雙向鏈表)。

5. 物件

typedef struct _zend_object_value {
    zend_object_handle handle;           // 無符號整數,物件池索引
    zend_object_handlers *handlers;      // 運算符處理函數表
} zend_object_value;

物件僅在運行時創建。handle 是全局物件池 EG(objects_store) 的索引;handlers 定義屬性讀寫、方法調用、複製、析構等行為。

四、弱類型的本質

PHP 變數不聲明類型,運行時由 zval.type 動態標識。同一變數可先存整數、後存字串,只需修改 type 與 value 對應欄位。這就是「容器兼容並包」的弱類型實現:統一容器 + 類型標籤 + 聯合體值。

五、引用計數與 Copy-on-Write

  • 賦值 $b = $a 時,zval.refcount++,雙方指向同一 zval。
  • 修改 $b = 2 時,檢測 refcount > 1,分離新 zval(Copy-on-Write),refcount--。
  • unset($a) 遞減 refcount,歸零時釋放記憶體。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved