静态属性存储在 zend_class_entry 结构体的 static_members_table 数组中,与类绑定、请求周期同寿;其元信息存于 default_static_members_table,值按索引对齐;编译期限定字面量初始化,运行时通过类指针查哈希定位 zval。

PHP 7.4.25 中,类的静态属性并不存储在对象(zend_object)实例里,而是**绑定在类结构体 zend_class_entry 上**,作为其一部分长期驻留在内存中,生命周期与整个请求周期一致(Web SAPI 下每次请求初始化,CLI 下贯穿脚本执行)。
静态属性存在哪儿?
每个已加载的类对应一个 zend_class_entry * 指针,它内部包含一个字段:zend_property_info *default_static_members_table
该字段指向一个按声明顺序排列的静态属性元信息数组,记录名称、类型、访问控制等;而真正的值,则存放在另一个独立的数组中:zval *static_members_table
-
static_members_table是一个zval数组,索引与default_static_members_table对齐 - 每个
zval存储对应静态属性的当前值(如整数、字符串、数组等) - 该表在类首次被使用(如首次访问
ClassName::$prop)时惰性初始化,初始值来自编译期设定的默认值(字面量)
为什么不能用表达式初始化?
因为静态属性的默认值必须在编译阶段确定,写入 zend_class_entry 的常量区。源码中,PHP 编译器(zend_compile.c)在解析类定义时会校验:
- 只允许
const表达式:字符串、数字、null、数组字面量(PHP 7.4+ 支持)、常量引用(如self::CONST) - 禁止运行时函数调用(如
time())、变量插值、$this或任何需要执行上下文的表达式 - 违反则报错
Parse error: syntax error, unexpected 'time' (T_STRING)
访问时怎么找到它?
当执行 ClassName::$prop 或 self::$prop 时,Zend VM 不查对象,而是:
- 通过类名或当前作用域获取
zend_class_entry * - 查
zend_class_entry->static_members_table - 根据属性名哈希或线性查找(取决于是否启用属性缓存),定位到对应
zval *槽位 - 读/写该
zval,不涉及对象内存分配或实例化
和实例属性的根本区别
实例属性属于 zend_object 结构体中的 properties(PHP 7.4+ 还有优化的 typed property offset 存储),每个对象一份;而静态属性是类全局一份,所有实例共享同一份 zval 值 —— 修改任一地方,下次读就是新值,无拷贝、无同步开销,但也无隔离性。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











