我可以信任调用 PHP __destruct() 方法吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/151660/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I trust PHP __destruct() method to be called?
提问by Casey Watson
In PHP5, is the __destruct() method guaranteed to be called for each object instance? Can exceptions in the program prevent this from happening?
在 PHP5 中,是否保证为每个对象实例调用 __destruct() 方法?程序中的异常可以防止这种情况发生吗?
采纳答案by Geoff
The destructor will be called when the all references are freed, or when the script terminates. I assume this means when the script terminates properly. I would say that critical exceptions would not guarantee the destructor to be called.
当所有引用被释放或脚本终止时,析构函数将被调用。我认为这意味着脚本正确终止时。我会说关键异常不能保证调用析构函数。
The PHP documentationis a little bit thin, but it does say that Exceptions in the destructor will cause issues.
该PHP文件是有点薄,但它说,在析构函数中的异常会导致一些问题。
回答by Mark Biek
It's also worth mentioning that, in the case of a subclass that has its own destructor, the parent destructor is notcalled automatically.
还值得一提的是,在子类有自己的析构函数的情况下,不会自动调用父析构函数。
You have to explicitly call parent::__destruct()from the subclass __destruct()method if the parent class does any required cleanup.
如果父类执行任何所需的清理工作,您必须从子类__destruct()方法显式调用parent::__destruct()。
回答by Mikko Rantalainen
In my experience destructors will be always called in PHP 5.3, but be warned that if some piece of code calls exit() or if a fatal error occurs, PHP will call destructors in "any" order (I think the actual order is order in memory or the order the memory was reserved for the objects. In practice, this order is almost always problematic). This is referred as "shutdown sequence" in PHP documentation.
根据我的经验,在 PHP 5.3 中总是会调用析构函数,但请注意,如果某些代码调用 exit() 或发生致命错误,PHP 将按“任意”顺序调用析构函数(我认为实际顺序是内存或为对象保留内存的顺序。实际上,这种顺序几乎总是有问题的)。这在 PHP 文档中称为“关闭序列”。
PHP documentation of destructorssays:
PHP 5 introduces a destructor concept similar to that of other object-oriented languages, such as C++. The destructor method will be called as soon as there are no other references to a particular object, or in any order during the shutdown sequence.
PHP 5 引入了类似于其他面向对象语言(如 C++)的析构函数概念。只要没有其他对特定对象的引用,或在关闭序列期间以任何顺序调用析构函数方法。
As a result if you have class X which holds a reference to Y, the destructor of X may be called AFTER the destructor of Y has already been called. Hopefully, the reference to Y was not that important... Officially this is not a bug because it has been documented.
因此,如果您的类 X 持有对 Y 的引用,则 X 的析构函数可能会在 Y 的析构函数已经被调用之后被调用。希望对 Y 的引用不是那么重要...从官方角度来说,这不是错误,因为它已被记录在案。
However, it's very hard to workaround this issue because officially PHP provides no way to know if destructor is called normally (destructors are called in correct order) or destructors are called in "any" order where you cannot use data from referenced objects because those might have been already destroyed. One could workaround this lack of detection using debug_backtrace() and examining the stack. Lack of normal stack seems to imply "shutdown sequence" with PHP 5.3 but this, too, is undefined. If you have circular references, the destructors of those objects will not be called at all with PHP 5.2 or lesser and will be called in "any" order during "shutdown sequence" in PHP 5.3 or greater. For circular references, there does not exists a logically "correct" order so "any" order is good for those.
但是,很难解决这个问题,因为官方 PHP 没有提供任何方法来知道是否正常调用析构函数(以正确的顺序调用析构函数)或以“任何”顺序调用析构函数,在这种情况下您不能使用来自引用对象的数据,因为那些可能已经被摧毁了。可以使用 debug_backtrace() 并检查堆栈来解决这种检测不足的问题。缺少正常堆栈似乎意味着 PHP 5.3 的“关闭序列”,但这也是未定义的。如果您有循环引用,则这些对象的析构函数在 PHP 5.2 或更低版本中根本不会被调用,并且在 PHP 5.3 或更高版本中的“关闭序列”期间将以“任何”顺序调用。对于循环引用,不存在逻辑上“正确”的顺序,因此“任何”
There are some exceptions (this is PHP after all):
有一些例外(毕竟这是 PHP):
- if
exit()is called in another destructor, any remaining destructors will not be called (http://php.net/manual/en/language.oop5.decon.php) - if
FATALerror occurs anywhere (many possible causes, e.g. trying to throw an exception out from any other destructor could be one cause), any remaining destructors will not be called.
- 如果
exit()在另一个析构函数中调用,则不会调用任何剩余的析构函数(http://php.net/manual/en/language.oop5.decon.php) - 如果
FATAL错误发生在任何地方(许多可能的原因,例如试图从任何其他析构函数中抛出异常可能是一个原因),则不会调用任何剩余的析构函数。
Of course, if the PHP engine hits segmentation fault or some other internal bug occurs, then all bets are off.
当然,如果 PHP 引擎遇到分段错误或发生其他一些内部错误,那么所有赌注都将关闭。
If you want to understand currentimplementation of "shutdown sequence", see https://stackoverflow.com/a/14101767. Note that this implementation may change in future PHP versions.
如果您想了解“关闭序列”的当前实现,请参阅https://stackoverflow.com/a/14101767。请注意,此实现可能会在未来的 PHP 版本中更改。
回答by MOdMac
There is a current bug with circular references that stops the destruct method being called implicitly. http://bugs.php.net/bug.php?id=33595It should be fixed in 5.3
当前存在一个循环引用错误,该错误会阻止隐式调用 destruct 方法。http://bugs.php.net/bug.php?id=33595应该在5.3修复
回答by zupa
Use a shutdown function if you want to go for sure: register_shutdown_function()
如果您想确定,请使用关闭功能:register_shutdown_function()

