zend_hash_init_ex(&zend_standard_class_def.class_table, 10, NULL, ZEND_CLASS_DTOR, 1, 0);
zend_hash_init_ex(&zend_standard_class_def.function_table, 0, NULL, ZEND_FUNCTION_DTOR, 1, 0);
zend_standard_class_def.constructor = NULL;
+ zend_standard_class_def.destructor = NULL;
zend_standard_class_def.clone = NULL;
zend_standard_class_def.handle_function_call = NULL;
zend_standard_class_def.handle_property_get = NULL;
zend_function_entry *builtin_functions;
union _zend_function *constructor;
+ union _zend_function *destructor;
union _zend_function *clone;
/* handlers */
class_container.name_length = sizeof(class_name)-1; \
class_container.builtin_functions = functions; \
class_container.constructor = NULL; \
+ class_container.destructor = NULL; \
class_container.clone = NULL; \
class_container.handle_function_call = NULL; \
class_container.handle_property_get = NULL; \
class_container.name_length = sizeof(class_name)-1; \
class_container.builtin_functions = functions; \
class_container.constructor = NULL; \
+ class_container.destructor = NULL; \
class_container.clone = NULL; \
class_container.handle_function_call = handle_fcall; \
class_container.handle_property_get = handle_propget; \
zend_hash_update(&CG(active_class_entry)->function_table, name, name_len+1, &op_array, sizeof(zend_op_array), (void **) &CG(active_op_array));
if ((CG(active_class_entry)->name_length == (uint) name_len) && (!memcmp(CG(active_class_entry)->name, name, name_len))) {
CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array);
- } else if ((function_name->u.constant.value.str.len == sizeof("_construct")-1) && (!memcmp(function_name->u.constant.value.str.val, "_construct", sizeof("_clone")))) {
+ } else if ((function_name->u.constant.value.str.len == sizeof("_construct")-1) && (!memcmp(function_name->u.constant.value.str.val, "_construct", sizeof("_construct")))) {
CG(active_class_entry)->constructor = (zend_function *) CG(active_op_array);
+ } else if ((function_name->u.constant.value.str.len == sizeof("_destruct")-1) && (!memcmp(function_name->u.constant.value.str.val, "_destruct", sizeof("_destruct")))) {
+ CG(active_class_entry)->destructor = (zend_function *) CG(active_op_array);
} else if ((function_name->u.constant.value.str.len == sizeof("_clone")-1) && (!memcmp(function_name->u.constant.value.str.val, "_clone", sizeof("_clone")))) {
CG(active_class_entry)->clone = (zend_function *) CG(active_op_array);
}
zend_hash_init(&new_class_entry.constants_table, 10, NULL, ZVAL_PTR_DTOR, 0);
new_class_entry.constructor = NULL;
+ new_class_entry.destructor = NULL;
new_class_entry.clone = NULL;
new_class_entry.handle_function_call = NULL;
zend_hash_init(&new_class_entry.constants_table, 10, NULL, ZVAL_PTR_DTOR, 0);
new_class_entry.constructor = NULL;
+ new_class_entry.destructor = NULL;
new_class_entry.clone = NULL;
new_class_entry.handle_function_call = NULL;
zend_hash_copy(&new_class_entry.constants_table, &parent_class->constants_table, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
new_class_entry.constructor = parent_class->constructor;
+ new_class_entry.destructor = parent_class->destructor;
/* FIXME: What do we do with clone? */
efree(objects->object_buckets);
}
+static inline void zend_objects_destroy_object(zend_object *object, zend_object_handle handle TSRMLS_DC)
+{
+ if (object->ce->destructor) {
+ zval *obj;
+ zval *destructor_func_name;
+ zval *retval_ptr;
+ HashTable symbol_table;
+
+ MAKE_STD_ZVAL(obj);
+ obj->type = IS_OBJECT;
+ obj->value.obj.handle = handle;
+ obj->value.obj.handlers = &zoh;
+ zval_copy_ctor(obj);
+
+
+ /* FIXME: Optimize this so that we use the old_object->ce->destructor function pointer instead of the name */
+ MAKE_STD_ZVAL(destructor_func_name);
+ destructor_func_name->type = IS_STRING;
+ destructor_func_name->value.str.val = estrndup("_destruct", sizeof("_destruct")-1);
+ destructor_func_name->value.str.len = sizeof("_destruct")-1;
+
+ ZEND_INIT_SYMTABLE(&symbol_table);
+
+ call_user_function_ex(NULL, &obj, destructor_func_name, &retval_ptr, 0, NULL, 0, &symbol_table TSRMLS_CC);
+
+ zend_hash_destroy(&symbol_table);
+ zval_ptr_dtor(&obj);
+ zval_ptr_dtor(&destructor_func_name);
+ zval_ptr_dtor(&retval_ptr);
+ }
+
+ /* Nuke the object */
+ zend_hash_destroy(object->properties);
+ efree(object->properties);
+
+}
+
zend_object_value zend_objects_new(zend_object **object, zend_class_entry *class_type)
{
zend_object_handle handle;
handle = EG(objects).top++;
}
EG(objects).object_buckets[handle].valid = 1;
+ EG(objects).object_buckets[handle].constructor_called = 0;
EG(objects).object_buckets[handle].bucket.obj.refcount = 1;
*object = &EG(objects).object_buckets[handle].bucket.obj.object;
}
object = &EG(objects).object_buckets[handle].bucket.obj.object;
- zend_hash_destroy(object->properties);
- efree(object->properties);
+
+ if (!EG(objects).object_buckets[handle].constructor_called) {
+ EG(objects).object_buckets[handle].constructor_called = 1;
+ zend_objects_destroy_object(object, handle TSRMLS_CC);
+ }
+
EG(objects).object_buckets[handle].valid = 0;
+
#if ZEND_DEBUG_OBJECTS
fprintf(stderr, "Deleted object id #%d\n", handle);
#endif
zend_object *object;
if (EG(objects).object_buckets[handle].valid) {
- object = &EG(objects).object_buckets[handle].bucket.obj.object;
- zend_hash_destroy(object->properties);
- efree(object->properties);
+ if (!EG(objects).object_buckets[handle].constructor_called) {
+ object = &EG(objects).object_buckets[handle].bucket.obj.object;
+ EG(objects).object_buckets[handle].constructor_called = 1;
+ zend_objects_destroy_object(object, handle TSRMLS_CC);
+ }
+ }
+ /* FIXME: Optimizer this so that only if the constructor was called we recheck the refcount */
+ if (EG(objects).object_buckets[handle].bucket.obj.refcount == 0) {
+ EG(objects).object_buckets[handle].bucket.free_list.next = EG(objects).free_list_head;
+ EG(objects).free_list_head = handle;
+ EG(objects).object_buckets[handle].valid = 0;
}
- EG(objects).object_buckets[handle].bucket.free_list.next = EG(objects).free_list_head;
- EG(objects).free_list_head = handle;
- EG(objects).object_buckets[handle].valid = 0;
#if ZEND_DEBUG_OBJECTS
fprintf(stderr, "Deallocated object id #%d\n", handle);
#endif
typedef struct _zend_object_bucket {
zend_bool valid;
+ zend_bool constructor_called;
union _bucket {
struct {
zend_object object;