对象的实现
对象是类的实例,上面讲了类的源码实现,接下来讲对象的源码实现,并介绍和类相关的普通属性。
实现
先来看看对象的存储结构:
struct _zend_object {
zend_refcounted_h gc;
uint32_t handle;
zend_class_entry *ce;
const zend_object_handlers *handlers;
HashTable *properties;
zval properties_table[1];
};
struct _zend_object_handlers {
/* offset of real object header (usually zero) */
int offset;
/* general object functions */
zend_object_free_obj_t free_obj;
zend_object_dtor_obj_t dtor_obj;
zend_object_clone_obj_t clone_obj;
/* individual object functions */
zend_object_read_property_t read_property;
zend_object_write_property_t write_property;
zend_object_read_dimension_t read_dimension;
zend_object_write_dimension_t write_dimension;
zend_object_get_property_ptr_ptr_t get_property_ptr_ptr;
zend_object_get_t get;
zend_object_set_t set;
zend_object_has_property_t has_property;
zend_object_unset_property_t unset_property;
zend_object_has_dimension_t has_dimension;
zend_object_unset_dimension_t unset_dimension;
zend_object_get_properties_t get_properties;
zend_object_get_method_t get_method;
zend_object_call_method_t call_method;
zend_object_get_constructor_t get_constructor;
zend_object_get_class_name_t get_class_name;
zend_object_compare_t compare_objects;
zend_object_cast_t cast_object;
zend_object_count_elements_t count_elements;
zend_object_get_debug_info_t get_debug_info;
zend_object_get_closure_t get_closure;
zend_object_get_gc_t get_gc;
zend_object_do_operation_t do_operation;
zend_object_compare_zvals_t compare;
};
结构体 struct _zend_object
各个字段的说明如下。
-
gc
:gc
头部(详见第 3 章)。 -
handle
:每生成一个结构体zend_object
,会将其首地址存储在全局变量executor_globals.objects_store.object_buckets
中,而handle
即为此结构体在此全局变量中的索引。 -
ce
:所属的类结构体指针。 -
handlers
:初始化时,默认指向全局变量std_object_handlers
,存储着包括操作对象属性等的多个指针函数。 -
properties
:HashTable 结构,存储对象的动态普通属性值。 -
properties_table
:柔性数组,存储对象的普通属性值。在初始化时创建,数组大小为对象所属类的默认普通属性个数default_properties_count+1
。
接下来,创建一个对象 Php7,其生成的数据结构示意图如图6-4所示。
$obj = new Php7();

普通属性
普通属性也存储在对象中。当查找对象的普通属性时,在其所属的类的变量 properties_info
中,根据属性名 key
,找到 value
(类型为 zend_property_info
结构体),判断属性后,结构体的字段 offset
即为要查找到的属性值在对象的 properties_table
中的地址偏移量,如图6-5所示。
看上去顺利地解决了普通属性的存储问题,其实不然。请看下段代码:
$php = new Php7();
$php->filename = "beatles.php";
基于 PHP 的特性,对象中还存在一种动态普通属性。当然了,由于动态普通属性没有权限问题,也不需要在对象创建时初始化,所以比较简单,直接存储到对象的 properties
字段就好了。