PHP 所有變數在 C 層統一用 zval 結構體:
struct _zval_struct {
zvalue_value value; // 聯合體:存實際值
zend_uint refcount__gc; // 引用計數(GC 用)
zend_uchar type; // 類型標記 IS_LONG, IS_STRING, IS_ARRAY...
zend_uchar is_ref__gc; // 是否為引用 (&)
};
typedef union _zvalue_value {
long lval; // 整數、布爾、資源 ID
double dval; // 浮點數
struct { // 字串
char *val;
int len;
} str;
HashTable *ht; // 陣列
zend_object_value obj; // 物件
} zvalue_value;
同一時刻只佔用一個欄位,實現「弱類型」動態切換。
| 常量 | 值 | 對應欄位 |
|---|---|---|
| IS_NULL | 0 | — |
| IS_LONG | 1 | lval |
| IS_DOUBLE | 2 | dval |
| IS_BOOL | 3 | lval (0/1) |
| IS_RESOURCE | 4 | lval (資源 ID) |
| IS_STRING | 5 | str |
| IS_ARRAY | 6 | ht |
| IS_OBJECT | 7 | obj |
typedef struct _hashtable {
uint nTableSize; // 槽位數,2 的冪,最小 8
uint nTableMask; // nTableSize - 1,用 & 代替 %
uint nNumOfElements; // 當前元素數,count() 直接讀取
ulong nNextFreeElement; // 下一個數字索引
Bucket *pInternalPointer; // foreach 指針
Bucket *pListHead; // 雙向鏈表頭(維持插入順序)
Bucket *pListTail; // 鏈表尾
Bucket **arBuckets; // 槽位陣列
dtor_func_t pDestructor;// 元素刪除回調
zend_bool persistent; // 內存分配方式
unsigned char nApplyCount; // 遞歸保護計數
zend_bool bApplyProtection;
} HashTable;
typedef struct bucket {
ulong h; // 字串 key 的哈希值,或數字索引
uint nKeyLength; // key 長度,數字索引為 0
void *pData; // 指向值(通常是拷貝),指針陣列指向 pDataPtr
void *pDataPtr; // 若值為指針,此處存真實指針
Bucket *pListNext; // 全域鏈表下一個
Bucket *pListLast; // 全域鏈表上一個
Bucket *pNext; // 同槽位鏈表下一個
Bucket *pLast; // 同槽位鏈表上一個
char arKey[1]; // 變長結構體:存字串 key
} Bucket;
static inline ulong zend_inline_hash_func(const char *arKey, uint nKeyLength) {
register ulong hash = 5381;
for (uint i = 0; i < nKeyLength; i++) {
hash = ((hash << 5) + hash) + arKey[i]; // hash * 33 + c
}
return hash;
}
nIndex = h & nTableMask(位運算比取模快)pNext/pLast 鏈表解決nNumOfElements > nTableSize,擴容為 2 倍並重新哈希typedef struct _zend_object_value {
zend_object_handle handle; // 物件句柄(整數 ID)
zend_object_handlers *handlers; // 方法表指針
} zend_object_value;
EG(objects_store).object_buckets[handle] 獲取實際 zend_objectzend_object 包含屬性 HashTable、類項指針、引用計數handlers->get_method() 解析方法EG(symbol_table) (HashTable)EG(active_symbol_table),函數調用時切換$GLOBALS 直接指向全域符號表PHP 變數底層:zval (類型+值+引用計數) + HashTable (陣列/符號表) + Bucket (鏈表+雙向列表) + DJBX33A 哈希。理解這套結構,即可洞悉 count() O(1)、foreach 依賴內部指針、引用計數 GC、陣列插入順序保持等所有行為本質。