下面的代码说明了两次调用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
答案 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
在代码完成之前,对象会被破坏。如果不是那么输出的顺序就会被反转。