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

深入理解 PHP 內核(七):變量與資料類型——常量實現詳解

     編輯:關於C語言

常量內部結構

PHP 常量在變量 zval 基礎上增加標記、名稱、模組號:

typedef struct _zend_constant {
    zval value;        // zval 結構,儲存常量值
    int flags;         // 標記:CONST_PERSISTENT | CONST_CS
    char *name;        // 常量名稱
    uint name_len;     // 名稱長度
    int module_number; // 所屬模組號
} zend_constant;

定義於 Zend/zend_constants.h 第 33 行。

define() 定義常量流程

內建函數 define() 實現於 Zend/zend_builtin_functions.c:

ZEND_FUNCTION(define) {
    // 1. 解析參數:name, value, case_insensitive
    // 2. 處理類常量(略)
    // 3. 填充 zend_constant 結構
    c.value = *val;
    zval_copy_ctor(&c.value);
    c.flags = case_sensitive;          // 預設 CONST_CS(大小寫敏感)
    c.name = zend_strndup(name, name_len);
    c.name_len = name_len + 1;
    c.module_number = PHP_USER_CONSTANT;
    // 4. 註冊到常量表
    if (zend_register_constant(&c TSRMLS_CC) == SUCCESS) RETURN_TRUE;
    else RETURN_FALSE;
}

大小寫敏感由第三參數控制:non_cs=true → flags=0,否則 flags=CONST_CS。PHP 對常量名稱無命名限制。

defined() 判斷常量是否存在

同文件實現,調用 zend_get_constant_ex() → zend_get_constant(),核心為 HashTable 查找:

zend_hash_find(EG(zend_constants), name, name_len+1, (void**)&c)

查找前後對名稱有特殊處理(如命名空間解析)。

標準常量初始化

CGI 模式啟動鏈:
php_cgi_startup() → php_module_startup() → zend_startup() → zend_register_standard_constants()

void zend_register_standard_constants(TSRMLS_D) {
    REGISTER_MAIN_LONG_CONSTANT("E_ALL", E_ALL, CONST_PERSISTENT | CONST_CS);
    // ... 其他核心常量
}

REGISTER_MAIN_LONG_CONSTANT 展開為 zend_register_long_constant(),構造 zend_constant 並註冊。模組號為核心模組編號,flags 含 CONST_PERSISTENT(請求間持久)。

常量註冊核心:zend_register_constant()

  1. 依 flags 判斷大小寫:不敏感則名稱轉小寫;含 \ 也轉小寫。
  2. 插入全域常量表 EG(zend_constants)(HashTable):
zend_hash_add(EG(zend_constants), name, c->name_len, (void*)c, sizeof(zend_constant), NULL)

模組啟動階段的額外常量

php_module_startup() 中亦註冊 PHP_VERSION、PHP_OS 等用戶層常量(模組號 PHP_USER_CONSTANT)。

總結

PHP 常量本質是帶擴展元資料的 zval,存儲於全域 HashTable。定義、查找、啟動註冊均圍繞 zend_constant 結構與 zend_register_constant() 展開。理解此機制,有助於編寫擴展時正確管理常量生命週期。

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