【问题标题】:When (at which moment) is __destruct called?何时(在哪一刻)调用 __destruct?
【发布时间】:2014-05-11 17:32:23
【问题描述】:

在考虑没有引用循环的简单对象时,调用 __destruct 是否有一些保证?我从java中知道,它没有定义何时以及是否调用函数finalize,它取决于垃圾收集器。

例如,如果您有这样的功能:

1   function test(){
2       $x = new SomeObject();
3       $y = new SomeObject();
4       $x = null;
5   }

SomeObject 没有引用循环。

你能假设 $x->__destruct 在第 4 行被调用,$y->__destruct 在第 5 行被调用吗?

测试以下脚本似乎表明这是真的: https://gist.github.com/KAYLukas/0b1d65e57b52862f8da5

此外,SplFileObject 似乎适用于这个谓词:不可能关闭文件,而只需将变量设置为 null。如果这不会直接调用__destruct,那么在使用SplFileObject 打开文件后,就不可能可靠地打开文件。

我发现可以保证最终会调用__destruct,而不是何时。

【问题讨论】:

标签: php garbage-collection reference-counting


【解决方案1】:

是的,你可以假设。

__destruct 总是在对对象的最后一个引用消失的那一刻被调用:当您无法再以任何方式从外部访问该对象时。

如果存在循环引用,你需要等到它循环垃圾收集器进来,它没有定义在什么时候发生。

如果您也将对象存储在其他地方,则需要在调用析构函数之前先将其从那里删除。

更多信息:内部对象并不总是在__destruct(用户可能直接调用它)上销毁其资源,但仅在对象真正被销毁时才销毁。 (防止段错误的技术措施)

同样在关闭期间,第一个变量和数组会按照它们定义的反向顺序被删除,并且在对对象的最后一个引用消失的地方,该对象被销毁。然后循环垃圾收集器进来并删除其他对象并在那里调用__destruct

这里唯一未定义的是循环垃圾收集器删除对象并调用它们的__destruct函数的顺序。

【讨论】:

  • '当您无法从外部以任何方式访问该对象时。'不完全正确,请考虑对象:gist.github.com/KAYLukas/5d91aa17c6173f426a7d。只有在运行 gc(循环引用收集器)时才会调用析构函数。无论如何,(samitha 评论文档)文档说:“只要没有其他对特定对象的引用,或者在关闭序列期间以任何顺序调用,就会调用析构函数方法。”因此,如果您更新答案,我会接受。
  • @user23127 实际上,我的回答中已经隐含地说明了其中的大部分内容。但我已经用信息更新了它。同样在关机期间,它不是按任何顺序,而是按已知顺序,但只是没有记录。
  • @user23127 小错误,变量实际上以相反的顺序被销毁,lxr.php.net/xref/PHP_TRUNK/Zend/zend_execute_API.c#247 纠正了这一点。
  • 出于我的目的,我现在不考虑它是如何完成的——这很容易通过测试发现——但如果它被记录在案,因此在后续更新中不会改变。跨度>
  • @user23127 实际上,这里的大多数内容都没有记录,并且实际上可能会发生变化。但据我现在所知,(作为 php-src 的贡献者)实际上并没有改变它的计划。所以我认为至少接下来的两个版本应该是安全的。
猜你喜欢
  • 2015-03-12
  • 1970-01-01
  • 1970-01-01
  • 2020-04-16
  • 2018-03-19
  • 2016-08-10
  • 2022-01-17
  • 2010-09-14
  • 2015-09-15
相关资源
最近更新 更多