PHP类构造函数中的作用域展开 [英] Scope unwinding in PHP class constructors

查看:107
本文介绍了PHP类构造函数中的作用域展开的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在学习PHP类和异常,并且来自C ++背景,以下内容使我感到奇怪:

I'm learning PHP classes and exceptions, and, coming from a C++ background, the following strikes me as odd:

派生类的构造函数抛出异常时例外,看来基类的析构函数不会自动运行:

When the constructor of a derived class throws an exception, it appears that the destructor of the base class is not run automatically:

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的类层次结构中实现正确的作用域展开,以便在发生异常时正确地破坏子对象?

On the other hand, the destructors of member objects are executed properly if there is an exception in the constructor (at #1). Now I wonder: How do you implement correct scope unwinding in a class hierarchy in PHP, so that subobjects are properly destroyed in the event of an exception?

在所有成员对象被销毁后(#2 ),无法运行基本析构函数。也就是说,如果我们删除行#1 ,我们将得到:

Also, it seems that there's no way to run the base destructor after all the member objects have been destroyed (at #2). To wit, if we remove line #1, we get:

Base const.
Foo const.
Der const.
Der destr.
Base destr.
Foo destr.    // ouch!!

如何解决这个问题?

更新:我仍然愿意接受进一步的贡献。如果有人有充分的理由说明为什么PHP对象系统从不不需要一个正确的销毁顺序,我将为此提供另一笔赏金(或其他有说服力的答案)。

Update: I'm still open to further contributions. If someone has a good justification why the PHP object system never requires a correct destruction sequence, I'll give out another bounty for that (or just for any other convincingly argued answer).

推荐答案

我想解释一下PHP为什么如此行事以及为什么它实际上有意义。

I would like to explain why PHP behaves this way and why it actually makes (some) sense.

在PHP 中,只要没有更多引用,对象就会被销毁。引用可以通过多种方式删除,例如通过 unset()通过保留范围或作为关闭的一部分来设置变量。

In PHP an object is destroyed as soon as there are no more references to it. A reference can be removed in a multitude of ways, e.g. by unset()ing a variable, by leaving scope or as part of shutdown.

如果您理解这一点,您可以很容易地了解这里发生的情况(我将首先解释没有例外的情况):

If you understood this, you can easily understand what happens here (I'll explain the case without the Exception first):


  1. PHP进入关闭状态,因此所有变量引用

  2. $ x 创建的引用(对于 Der
  3. 调用派生的析构函数,它调用基本析构函数。

  4. 现在从<删除 Foo 实例的code> $ this-> foo (作为销毁成员字段的一部分。)

  5. 也没有对 Foo 的引用,因此它也被销毁并调用析构函数。

  1. PHP enters shutdown, thus all variable references are removed.
  2. When the reference created by $x (to the instance of Der) is removed the object is destroyed.
  3. The derived destructor is called, which calls the base destructor.
  4. Now the reference from $this->foo to the Foo instance is removed (as part of destroying the member fields.)
  5. There aren't any more references to Foo either, so it is destroyed too and the destructor is called.

想象一下,这种方法将无法正常工作,并且在调用析构函数之前,成员字段将被销毁:您无法再在析构函数中访问它们。我严重怀疑C ++中是否存在这种行为。

Imagine this would not work this way and member fields would be destroyed before calling the destructor: You couldn't access them anymore in the destructor. I seriously doubt that there is such a behavior in C++.

在Exception情况下,您需要了解,对于PHP从来没有真正存在过该类的实例,因为构造函数永不返回。

In the Exception case you need to understand that for PHP there never really existed an instance of the class, as the constructor never returned. How can you destruct something that was never constructed?

如何解决?

您不知道。您仅需要一个析构函数的事实可能是不良设计的标志。而且销毁令对您来说至关重要,甚至更多。

You don't. The mere fact that you need a destructor probably is a sign of bad design. And the fact that the destruction order matters that much to you, is even more.

这篇关于PHP类构造函数中的作用域展开的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆