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() 實現於 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 對常量名稱無命名限制。
同文件實現,調用 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(請求間持久)。
flags 判斷大小寫:不敏感則名稱轉小寫;含 \ 也轉小寫。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() 展開。理解此機制,有助於編寫擴展時正確管理常量生命週期。