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

PHP 核心原理解析:變數底層結構 zval、弱型別實現、Refcount 與 Copy-on-Write

     編輯:PHP 綜合知識

PHP 變數的 C 語言表示:zval

PHP 是用 C 實作的解釋器,所有變數在底層都是 zval 結構體(PHP 7 稱為 zval,PHP 5 為 zval* 指標)。

PHP 7+ zval 結構(簡化)

struct _zval_struct {
    zend_value        value;  // 聯合體:實際資料
    zend_refcount_h   refcount; // 參考計數
    zend_uchar        type;     // 型別標記
    zend_uchar        is_ref;   // 是否為參考
};

zend_value 聯合體(關鍵:弱型別實現)

typedef union _zend_value {
    zend_long         lval;   // 整數、布林
    double            dval;   // 浮點數
    zend_string      *str;    // 字串(指標)
    zend_array       *arr;    // 陣列
    zend_object      *obj;    // 物件
    zend_resource    *res;    // 資源
    zend_reference   *ref;    // 參考包裝
} zend_value;

弱型別本質:type 標記當前活躍的聯合體欄位,同一塊記憶體依 type 解讀為不同型別。變數賦值新值時,只需修改 type 與對應的聯合體欄位。

型別標記對應表

常數對應聯合體欄位PHP 型別
IS_LONGlvalint / bool
IS_DOUBLEdvalfloat
IS_STRINGstrstring
IS_ARRAYarrarray
IS_OBJECTobjobject
IS_RESOURCEresresource
IS_REFERENCEref參考包裝
IS_NULL—null

字串結構:zend_string

struct _zend_string {
    zend_refcount_h gc_refcount; // GC 參考計數
    zend_ulong      h;           // 預計算雜湊值
    size_t          len;         // 長度(不含結尾 \0)
    char            val[1];      // 柔性陣列成員,實際字元資料
};
  • 長度儲存於結構體,strlen() 直接讀取 len,O(1) 極快。
  • 參考計數支援 Copy-on-Write。

陣列結構:zend_array (HashTable)

  • 有序雜湊表,支援整數/字串鍵混合。
  • 鍵為字串時儲存 zend_string*,整數鍵直接儲存。
  • 插入/查找平均 O(1)。

參考計數與 Copy-on-Write (COW)

<?php
$a = "hello";      // 建立 zval(type=IS_STRING, refcount=1)
$b = $a;           // 指向同一 zval,refcount=2
$a = "world";      // 寫入前發現 refcount>1 → 複製新 zval,舊 zval refcount--,新 zval refcount=1
// 現在 $a、$b 指向不同 zval,互不影響
?>
  • 讀取不複製:賦值、函式傳遞(預設值傳遞)只增加 refcount。
  • 寫入才複製:修改變數時若 refcount > 1,觸發分離。
  • 參考 (&) 強制共用:is_ref=1,寫入不複製,直接修改共用 zval。

Resource 特殊處理

  • Resource 的 lval 儲存資源 ID(整數索引)。
  • 實際資源(檔案控制代碼、DB 連線、GD 圖片)儲存在全域資源表 EG(regular_list)。
  • Resource 不支援 Copy-on-Write 複製,故 var_export 回傳 NULL。

debug_zval_dump 觀察內部狀態

<?php
$a = 1;
debug_zval_dump($a); // long(1) refcount(2)  ← 參數傳遞增加 1
$b = $a;
debug_zval_dump($a); // long(1) refcount(3)
$a = 2;
debug_zval_dump($a); // long(2) refcount(2)  ← 分離後新 zval
debug_zval_dump($b); // long(1) refcount(2)
?>

總結

PHP 變數底層以 zval 統一表示,type 實現弱型別,refcount + is_ref 實現 Copy-on-Write 與參考語意。理解這機制能寫出高效能、低副作用的代碼,並看懂擴充套件開發文件。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved