]> granicus.if.org Git - php/commitdiff
- Experimental support for destructors. We need to see if destructors
authorAndi Gutmans <andi@php.net>
Thu, 27 Dec 2001 14:35:09 +0000 (14:35 +0000)
committerAndi Gutmans <andi@php.net>
Thu, 27 Dec 2001 14:35:09 +0000 (14:35 +0000)
- will actually work well in the context of PHP so we should consider this
- as experimental. Possible problems might be that when the constructor is
- run PHP might not be in a stable state.

Zend/zend.c
Zend/zend.h
Zend/zend_API.h
Zend/zend_compile.c
Zend/zend_objects.c
Zend/zend_objects.h

index ae58ac5f4b09142282ae92db4eaf22d090b3b4e5..cee2577ad95ff6f6628387978240adb51c2f019f 100644 (file)
@@ -257,6 +257,7 @@ static void register_standard_class(void)
        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;
index 88c92142991cd77cbb8beaac9116b9dabeb84fe6..6b90652ef32b669164794c2a992c8eb2fdfda100 100644 (file)
@@ -291,6 +291,7 @@ struct _zend_class_entry {
        zend_function_entry *builtin_functions;
 
        union _zend_function *constructor;
+       union _zend_function *destructor;
        union _zend_function *clone;
 
        /* handlers */
index 8b16c26586994cbbb5589602909e20eabba74f0c..5ae94c5e8f098b8e548aa48f6559a39c7aae13ee 100644 (file)
@@ -88,6 +88,7 @@
                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;   \
index 54871f825148ffbb14c673ffdbe5a43873113040..4e45411edfbed148e93cf5528be99a9a9327e892 100644 (file)
@@ -761,8 +761,10 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
                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);
                }
@@ -1361,6 +1363,7 @@ static void create_class(HashTable *class_table, char *name, int name_length, ze
        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;
@@ -1849,6 +1852,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod
        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;
@@ -1879,6 +1883,7 @@ void zend_do_begin_class_declaration(znode *class_token, znode *class_name, znod
                        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? */
 
index f86148158d19df1183d87e2aade74e82470e4896..776f7d9076dff6ec6137fb83ffe4a01332667367 100644 (file)
@@ -27,6 +27,43 @@ void zend_objects_destroy(zend_objects *objects)
        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;
@@ -45,6 +82,7 @@ zend_object_value zend_objects_new(zend_object **object, zend_class_entry *class
                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;
@@ -93,9 +131,14 @@ void zend_objects_delete_obj(zend_object_handle handle)
        }
 
        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
@@ -110,13 +153,18 @@ void zend_objects_del_ref(zend_object_handle handle)
                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
index 91e4d29276f9bbb9d55c2ca2c7845caef2f5a10d..b649163007733a3d8b008b8f176874854e56615a 100644 (file)
@@ -5,6 +5,7 @@
 
 typedef struct _zend_object_bucket {
        zend_bool valid;
+       zend_bool constructor_called;
        union _bucket {
                struct {
                        zend_object object;