【发布时间】:2011-11-20 05:19:10
【问题描述】:
我正在学习 PHP 类和异常,并且来自 C++ 背景,以下内容让我觉得很奇怪:
当派生类的构造函数抛出异常时,基类的析构函数似乎没有自动运行:
class Base
{
public function __construct() { print("Base const.\n"); }
public function __destruct() { print("Base destr.\n"); }
}
class Der extends Base
{
public function __construct()
{
parent::__construct();
$this->foo = new Foo;
print("Der const.\n");
throw new Exception("foo"); // #1
}
public function __destruct() { print("Der destr.\n"); parent::__destruct(); }
public $foo; // #2
}
class Foo
{
public function __construct() { print("Foo const.\n"); }
public function __destruct() { print("Foo destr.\n"); }
}
try {
$x = new Der;
} catch (Exception $e) {
}
打印出来:
Base const.
Foo const.
Der const.
Foo destr.
另一方面,如果构造函数中出现异常(#1),成员对象的析构函数会正确执行。现在我想知道:如何在 PHP 的类层次结构中实现正确的范围展开,以便在发生异常时正确销毁子对象?
此外,似乎没有办法在所有成员对象都被销毁后运行基础析构函数(#2)。也就是说,如果我们删除行#1,我们会得到:
Base const.
Foo const.
Der const.
Der destr.
Base destr.
Foo destr. // ouch!!
如何解决这个问题?
更新:我仍然愿意接受进一步的贡献。如果有人有充分的理由说明为什么 PHP 对象系统从不需要正确的销毁序列,我将为此提供另一个赏金(或只是为任何其他令人信服的争论答案)。
【问题讨论】:
-
我必须说我很少需要在 PHP 中实现析构函数,所以也许这不是什么大问题。不过,你确实提出了一个很好的问题。
-
@Jani:坦率地说,考虑到它们的设计方式,我理解你为什么真的不想想要使用析构函数。我只是想知道为什么他们似乎考虑得这么糟糕,以及除了“不要使用这部分语言”之外是否有任何常见的习惯用法来规避这个设计缺陷...... :-S
-
同意 Jani:在 PHP 中编写析构函数确实没有意义,因为没有什么可以泄漏的。来自 C++ 的您可能将析构函数视为一个经过深思熟虑的工具,用于解决它们不打算解决的问题。
-
@Jon:你能澄清一下吗?你的意思是析构函数是一个经过深思熟虑的概念,在惯用的时候很有用并且可以工作,还是你的意思是一个设计良好的 PHP 程序不应该使用析构函数?如果您对前者有很好的论据,请务必将其作为答案发布!
-
后者,我不会说“不应该使用析构函数”,因为它可能太强大了,我只是从经验来看:在我写 PHP 的 10 年里,我有从来不需要写一个。我和你一样希望看到第一种类型的答案。
标签: php exception stack-unwinding