Php Destruct被称为两次

时间:2011-03-05 03:00:01

标签: php oop destructor

下面的代码说明了两次调用destruct()。我想知道为什么?

class A {
    function hi(){ echo 'hi'; }
    function __destruct(){
        echo 'destroy';
    }
}
class B{
    public $this_ = '';
    function __construct(){
        $this->this_ = new A;
    }
    function __call($method, $params) {
          return call_user_func_array(array($this->this_, $method), $params);
    }
}

$b = new B;
$b->__destruct();

输出:

destroydestroy

修改

zneak和TomcatExodus都是正确的。如果我只是:

[..code..]
$b = new B;
$b->__destruct();
print 'end of script';

输出将显示:

destroyend of scriptdestroy

4 个答案:

答案 0 :(得分:13)

调用destruct不会破坏对象。你第一次用__destruct()调用它,然后当PHP脚本终止时,它会在清理时再次调用它。

如果您希望在脚本终止之前销毁该对象,unset()它。你应该只看到一次毁灭调用。


具体来说,您的班级B会创建一个类A的自包含实例。由于B也会通过__call()将方法调用路由到A对象,因此__destruct()上的B调用__destruct()正在调用A B 1}}; {{1}}没有定义析构函数并传递调用。

答案 1 :(得分:10)

由于B没有__destruct方法,因此会调用__call方法(您可以通过向echo "calling $method"方法添加__call之类的内容来验证此方法),然后将其转发到您的A对象。

但是,调用__destruct并不会破坏对象:它只调用应该与其销毁相关联的清理代码。因此,一旦到达脚本的末尾,当A对象实际被销毁时​​,将再次调用其__destruct方法。

如果您要删除B个对象,请使用unset($b)

答案 2 :(得分:2)

手动调用destructor是最糟糕的想法之一,尤其是在处理其他人的代码时。对象的逻辑从construct开始,经过methods并以destruct结束。在destruct上,对象可能需要进行一些清理,variables可能会失效。 在内部调用destruct时,由于成功unset($Object),该对象不再可用。当您手动执行此操作时,该对象仍然可以访问,但如果它自己进行了一些清理,则没有内部变量支持。

  

现在想想如果你手动调用destruct之后调用依赖于你过早失效的数据的对象上的方法会是怎样的。它打破了整个逻辑! 所以始终unset()让PHP做自己的事。

手动销毁(展示位置删除:))在C ++中非常棒如果您知道自己在做什么,尤其是与placement new结合使用。但是你必须在整个实现过程中保护自己,并确保在调用方法时确实拥有数据。如果你手动管理内存,你必须在破坏中保护自己,而不是删除指针TWICE并在此过程中崩溃。

内存管理在C ++中非常酷!我讨厌GC (垃圾收集器):)

--- RANT OVER ---

答案 3 :(得分:0)

您正在手动调用析构函数;但这并不意味着您要删除该对象。您只是调用一个方法,该方法只是和其他方法一样。

$b->__destruct()的调用会调用$b->this_的析构函数,因为$b没有明确的析构函数方法。

当脚本完成时,Zend引擎将所有实例化对象调用为其析构函数,然后执行例程清理,这涉及调用包含对象的析构函数,即在销毁$b之后,$b->this_必须被清除,为此,引擎会自动调用它的构造函数。

请注意,第二次调用不是由于$b的破坏,而是由于A实例的破坏。

手动销毁对象没有任何障碍,它确实释放了它的资源(除非对象被共享,然后GC不会销毁它,除非没有更多的引用;在PHP中没有弱引用)。

GC工作示例: http://codepad.org/7JDBoOKY

在代码完成之前,对象会被破坏。如果不是那么输出的顺序就会被反转。