说到zend的类和对象不得不说两个数据结构,一个是 zend_class_entry, 一个是_zend_object。
struct _zend_object {
zend_refcounted_h gc;
uint32_t handle; // TODO: may be removed ???
zend_class_entry *ce;
const zend_object_handlers *handlers;
HashTable *properties;
zval properties_table[1];
};
问题点: _zend_object 结构体中的handle的作用?
看源码的时候一直很纳闷这个handle是用来干嘛的呢? 就一个数值,对一个object有什么用呢, 后来在看swoole的源码的时候发现swoole用这个handle在作为全局对象存储 swoole_objects.array 的数组下标 。 swoole_objects的定义在 php_swoole.h中,存入swoole_objects是通过 swoole_set_object(zval *object, void *ptr) 函数处理的
通过上面的现象,猜测,这个handle可能是zend引擎对于当前程序一共有多少个object的一个计数,同时用这个计数用做array的索引,方便定位查找之类的。如果是这样的话handle的值可能就是 1,2,3....1000 这样的数值 , 体现的应该是zend引擎对于对象的管理逻辑
求解
涉及到的对象操作的文件
- zend_objects.h
- zend_objects.c
- zend_objects_API.h
- zend_objects_API.c
对象操作的方法
ZEND_API void zend_object_std_init(zend_object *object, zend_class_entry *ce);
ZEND_API void zend_object_std_dtor(zend_object *object);
ZEND_API zend_object *zend_objects_new(zend_class_entry *ce);
ZEND_API void zend_objects_destroy_object(zend_object *object);
ZEND_API void zend_objects_clone_members(zend_object *new_object, zend_object *old_object);
ZEND_API zend_object *zend_objects_clone_obj(zval *object);
我们就从 zend_object_std_init 新建object 来看
ZEND_API void zend_object_std_init(zend_object *object, zend_class_entry *ce)
{
zval *p, *end;
GC_REFCOUNT(object) = 1;
GC_TYPE_INFO(object) = IS_OBJECT;
object->ce = ce;
object->properties = NULL;
zend_objects_store_put(object); //handle的处理
p = object->properties_table;
if (EXPECTED(ce->default_properties_count != 0)) {
end = p + ce->default_properties_count;
do {
ZVAL_UNDEF(p);
p++;
} while (p != end);
}
if (UNEXPECTED(ce->ce_flags & ZEND_ACC_USE_GUARDS)) {
GC_FLAGS(object) |= IS_OBJ_USE_GUARDS;
ZVAL_UNDEF(p);
}
}
init函数中有这么一句 zend_objects_store_put(object); , 这个函数里对handle做了处理, 这里面涉及到一个全局变量 EG(objects_store) , 这个全局变量中就存储了所有的objects
ZEND_API void zend_objects_store_put(zend_object *object)
{
int handle;
if (EG(objects_store).free_list_head != -1) {
handle = EG(objects_store).free_list_head;
EG(objects_store).free_list_head = GET_OBJ_BUCKET_NUMBER(EG(objects_store).object_buckets[handle]);
} else {
if (EG(objects_store).top == EG(objects_store).size) {
EG(objects_store).size <<= 1;
EG(objects_store).object_buckets = (zend_object **) erealloc(EG(objects_store).object_buckets, EG(objects_store).size * sizeof(zend_object*));
}
handle = EG(objects_store).top++;
}
object->handle = handle;
EG(objects_store).object_buckets[handle] = object;
}
通过上面的跟踪也就大概明白了这个handle的作用, 其实就是用来作为 EG(objects_store).object_buckets数组的下标
网友评论