]> granicus.if.org Git - php/commitdiff
Fixed bug #36759 (Objects destructors are invoked in wrong order when script is finis...
authorDmitry Stogov <dmitry@php.net>
Wed, 12 Jul 2006 07:54:00 +0000 (07:54 +0000)
committerDmitry Stogov <dmitry@php.net>
Wed, 12 Jul 2006 07:54:00 +0000 (07:54 +0000)
NEWS
Zend/tests/bug36759.phpt [new file with mode: 0755]
Zend/zend_execute_API.c

diff --git a/NEWS b/NEWS
index 9c82673f9acd18c41c3de5370074fd87fa8ce5f2..93be7adf055d17de959bfae766d02f7702bfe843 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -171,6 +171,8 @@ PHP                                                                        NEWS
 - Fixed bug #37244 (Added strict flag to base64_decode() that enforces 
   RFC3548 compliance). (Ilia)
 - Fixed bug #36949 (invalid internal mysqli objects dtor). (Mike)
+- Fixed bug #36759 (Objects destructors are invoked in wrong order when script
+  is finished). (Dmitry)
 - Fixed bug #36630 (umask not reset at the end of the request). (Ilia)
 - Fixed bug #35886 (file_get_contents() fails with some
   combinations of offset & maxlen). (Nuno)
diff --git a/Zend/tests/bug36759.phpt b/Zend/tests/bug36759.phpt
new file mode 100755 (executable)
index 0000000..8aa9977
--- /dev/null
@@ -0,0 +1,27 @@
+--TEST--
+Bug #36759 (Objects destructors are invoked in wrong order when script is finished)
+--FILE--
+<?php
+class Foo {
+  private $bar;
+  function __construct($bar) {
+    $this->bar = $bar;
+  }
+  function __destruct() {
+    echo __METHOD__,"\n";
+    unset($this->bar);
+  }
+}
+
+class Bar {
+  function __destruct() {
+    echo __METHOD__,"\n";
+    unset($this->bar);
+  }
+}
+$y = new Bar();
+$x = new Foo($y);
+?>
+--EXPECT--
+Foo::__destruct
+Bar::__destruct
index 142cc0e371d3f7741c13ac432cb4a23c50934f7f..4170a30e7c1a527602823e19f29aebdb31c92bf1 100644 (file)
@@ -190,8 +190,22 @@ void init_executor(TSRMLS_D)
        EG(This) = NULL;
 }
 
+static int zval_call_destructor(zval **zv TSRMLS_DC)
+{
+       if (Z_TYPE_PP(zv) == IS_OBJECT && (*zv)->refcount == 1) {
+               return ZEND_HASH_APPLY_REMOVE;
+       } else {
+               return ZEND_HASH_APPLY_KEEP;
+       }
+}
+
 void shutdown_destructors(TSRMLS_D) {
        zend_try {
+               int symbols;
+               do {
+                       symbols = zend_hash_num_elements(&EG(symbol_table));
+                       zend_hash_reverse_apply(&EG(symbol_table), (apply_func_t) zval_call_destructor TSRMLS_CC);
+               } while (symbols != zend_hash_num_elements(&EG(symbol_table)));
                zend_objects_store_call_destructors(&EG(objects_store) TSRMLS_CC);
        } zend_catch {
                /* if we couldn't destruct cleanly, mark all objects as destructed anyway */