- 属性可以在定义的时候初始化,但是必须是固定值,不可以是变量,也不可以依赖运行时信息。比如
protected $time = time();
就是不合法的。
- 成员属性分为两类:静态和非静态(普通属性)。静态属性使用
::
进行访问,普通属性使用->
进行访问。静态属性为各个对象共享的,与常量类似。而普通属性则是各个对象独享的。与常量存储方式不同,属性并非以属性名为索引存储在HashTable
中,而是通过数组保存的。静态属性保存在default_static_members_table
中,以default_static_members_count
表示长度;普通属性保存在default_properties_table
中,以default_properties_count
表示长度。
- 静态属性保存在类中,普通属性保存在对象中。静态属性保存在
zend_class_entry->default_static_members_table
中,而保存在zend_class_entry->default_properties_table
中的普通属性仅用于初始化对象,在对象实例化之后会被拷贝到zend_object
中,也就是普通属性实际保存在对象空间内。
zend_property_info
结构用于存储属性的信息。default_static_members_table
和default_properties_table
中只是存储属性的值,而属性的访问权限,属性名,静态属性值下标,非静态属性值的内存offset
等,都存储在zend_property_info
中(即zend_class_entry->properties_info
,这是一个HashTable
,key
就是属性名)。zend_property_info
的关键成员有如下几个:
name
:属性名,private
和protected
属性会做一些特殊处理。private
属性会在属性名之前加上类名,protected
属性会在属性名前加上*
offset
:对于普通成员属性,此处代表内存的offset
,与CV
变量的操作数相同,他们分配在zend_object
结构上。读取时,根据zend_object地址 + offset
进行获取。对于静态成员属性,则代表default_static_members_table
的数值索引,如:0
,1
,2
…
flag
:有两个含义。一:区分属性是静态还是非静态。二:标记属性的权限,即:public
、protected
和private
- 使用
zend_property_info->offset
获取属性值的时候,静态属性的值从zend_class_entry.default_static_members_table[offset]
进行获取;而普通属性的值则使用((char*)zend_object) + offset
来获取
- 静态属性读取步骤,以访问
self::$property_3
为例:
Step1
:根据字符串property_3
检索properties_info
,查找该属性的zend_property_info
结构Step2
:从zend_property_info
判定该属性为静态属性Step3
:以zend_property_info->offset
为下标(比如说本次为0
),在default_static_members_table
中查找default_static_members_table[0]
- 普通属性在继承的时候,子类可以重新初始化继承来的属性的值(
private
属性不支持继承,但可以重新定义,级别也无所谓,三个级别都可以),但是访问权限只能被放大而不能被缩小。如父类为protected
,子类可以为protected
或public
;如果父类是public
,则子类只能为public
。
- 静态属性在继承的时候,子类可以重新初始化继承来的属性的值(
private
属性不支持继承,但可以重新定义,级别也无所谓,三个级别都可以),但是访问权限只能被放大而不能被缩小。如父类为protected
,子类可以为protected
或public
;如果父类是public
,则子类只能为public
,也不能遗漏static
修饰符。