我正在学习
@L_301_0@类和例外,而从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这样做,为什么它实际上(某些)有意义.
在PHP中,只要没有更多的引用,对象就被销毁.参考可以通过多种方式去除,例如通过取消设置()变量,通过保留范围或作为关闭的一部分.
如果你明白这一点,你可以很容易的理解这里发生了什么(我将首先解释没有Exception的情况):
> PHP进入关机,因此所有的变量引用被删除.
>当$x(对Der的实例)创建的引用被删除时,对象被销毁.
>派生析构函数被调用,它调用基本析构函数.
>现在,从$this-> foo到Foo实例的引用被删除(作为摧毁成员字段的一部分).
>没有任何对Foo的引用,所以它也被破坏,析构函数被调用.
想象一下,这不会以这种方式工作,成员字段将在调用析构函数之前被销毁:在析构函数中不能访问它们.我非常怀疑C中有这样的行为.
在异常情况下,您需要了解,对于PHP,从来没有真正存在类的实例,因为构造函数从未返回.你怎么能破坏从未构建过的东西?
如何解决?
你没有您只需要一个析构函数的事实可能就是设计不好的一个迹象.而毁灭令对你来说很重要的事实更是如此.