object与string、array等类型不同,它是个符合类型,所以它的销毁过程更加复杂,赋值、函数调用结束或主动unset等操作中如果发现object引用计数为0则将触发销毁动作。
//情况1
$obj1 = new my_function();
$obj1 = 123; //此时将断开对zend_object的引用,如果refcount=0则销毁
//情况2
function xxxx(){
$obj1 = new my_function();
...
return null; //清理局部变量时如果发现$obj1引用为0则销毁
}
//情况3
$obj1 = new my_function();
//整个脚本结束,清理全局变量时
//情况4
$obj1 = new my_function();
unset($obj1);
上面这几个都是比较常见的会进行变量销毁的情况,销毁一个对象由zend_objects_store_del()
完成,销毁的过程主要是清理成员属性、从EG(objects_store).object_buckets中删除、释放zend_object内存等等。
//zend_objects_API.c
ZEND_API void zend_objects_store_del(zend_object *object)
{
//这个函数if嵌套写的很挫...
...
if (GC_REFCOUNT(object) > 0) {
GC_REFCOUNT(object)--;
return;
}
...
//调用dtor_obj,默认zend_objects_destroy_object()
//接着调用free_obj,默认zend_object_std_dtor()
object->handlers->dtor_obj(object);
object->handlers->free_obj(object);
...
ptr = ((char*)object) - object->handlers->offset;
efree(ptr);
}
另外,在减少refcount时如果发现object的引用计数大于0那么并不是什么都不做了,还记得2.1.3.4介绍的垃圾回收吗?PHP变量类型有的会因为循环引用导致正常的gc无法生效,这种类型的变量就有可能成为垃圾,所以会对这些类型的zval.u1.type_flag
打上IS_TYPE_COLLECTABLE
标签,然后在减少引用时即使refcount大于0也会启动垃圾检查,目前只有object、array两种类型会使用这种机制。