In PHP5, is the __destruct() method guaranteed to be called for each object instance? Can exceptions in the program prevent this from happening?
在PHP5中,__destruction()方法是否保证要为每个对象实例调用?程序中的异常可以防止这种情况发生吗?
5 个解决方案
#1
35
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 documentation is a little bit thin, but it does say that Exceptions in the destructor will cause issues.
PHP文档有点少,但是它确实说析构函数中的异常会引起问题。
#2
41
It's also worth mentioning that, in the case of a subclass that has its own destructor, the parent destructor is not called automatically.
值得一提的是,对于具有自己析构函数的子类,父析构函数不会自动调用。
You have to explicitly call parent::__destruct() from the subclass __destruct() method if the parent class does any required cleanup.
如果父类执行任何必需的清理,则必须显式地从子类__destroy()方法中调用parent:: __destruction()。
#3
11
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 destructors says:
析构函数的PHP文档说:
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.
因此,如果您有一个包含Y引用的X类,那么X的析构函数可以在已经调用Y的析构函数之后调用。希望,对Y的引用没有那么重要…正式地说,这不是一个bug,因为它已经被文档化了。
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) - 如果在另一个析构函数中调用exit(),则不会调用任何剩余的析构函数(http://php.net/manual/en/language.oop5.decon.php)
- if
FATAL
error occurs anywhere (many possible causes, e.g. trying to throw an exception out from any other destructor could be one cause) - 如果致命错误发生在任何地方(许多可能的原因,例如试图从任何其他析构函数抛出异常可能是一个原因)
Of course, if the PHP engine hits segmentation fault or some other internal bug occurs, then all bets are off.
当然,如果PHP引擎出现分割错误或其他内部错误,那么所有的赌注都将落空。
#4
10
There is a current bug with circular references that stops the destruct method being called implicitly. http://bugs.php.net/bug.php?id=33595 It should be fixed in 5.3
有一个带有循环引用的当前bug,它阻止隐式调用析构方法。http://bugs.php.net/bug.php?id=33595应该在5.3中固定
#5
8
Use a shutdown function if you want to go for sure: register_shutdown_function()
如果想要确认,请使用shutdown函数:register_shutdown_function()
#1
35
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 documentation is a little bit thin, but it does say that Exceptions in the destructor will cause issues.
PHP文档有点少,但是它确实说析构函数中的异常会引起问题。
#2
41
It's also worth mentioning that, in the case of a subclass that has its own destructor, the parent destructor is not called automatically.
值得一提的是,对于具有自己析构函数的子类,父析构函数不会自动调用。
You have to explicitly call parent::__destruct() from the subclass __destruct() method if the parent class does any required cleanup.
如果父类执行任何必需的清理,则必须显式地从子类__destroy()方法中调用parent:: __destruction()。
#3
11
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 destructors says:
析构函数的PHP文档说:
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.
因此,如果您有一个包含Y引用的X类,那么X的析构函数可以在已经调用Y的析构函数之后调用。希望,对Y的引用没有那么重要…正式地说,这不是一个bug,因为它已经被文档化了。
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) - 如果在另一个析构函数中调用exit(),则不会调用任何剩余的析构函数(http://php.net/manual/en/language.oop5.decon.php)
- if
FATAL
error occurs anywhere (many possible causes, e.g. trying to throw an exception out from any other destructor could be one cause) - 如果致命错误发生在任何地方(许多可能的原因,例如试图从任何其他析构函数抛出异常可能是一个原因)
Of course, if the PHP engine hits segmentation fault or some other internal bug occurs, then all bets are off.
当然,如果PHP引擎出现分割错误或其他内部错误,那么所有的赌注都将落空。
#4
10
There is a current bug with circular references that stops the destruct method being called implicitly. http://bugs.php.net/bug.php?id=33595 It should be fixed in 5.3
有一个带有循环引用的当前bug,它阻止隐式调用析构方法。http://bugs.php.net/bug.php?id=33595应该在5.3中固定
#5
8
Use a shutdown function if you want to go for sure: register_shutdown_function()
如果想要确认,请使用shutdown函数:register_shutdown_function()