【问题标题】:When is the destructor called in PHP?什么时候在 PHP 中调用析构函数?
【发布时间】:2021-02-16 00:28:34
【问题描述】:

我已阅读此答案:

Is destructor in PHP predictable?

但仍然不能 100% 确信 只要对象超出范围就调用析构函数。

我的用例如下:

class Transaction
{
    private $isComplete = false;

    public function commit() {
        // ...

        $this->isComplete = true;
    }

    public function rollBack() {
        // ...

        $this->isComplete = true;
    }

    public function __destruct() {
        if (! $this->isComplete) {
            $this->rollBack();
        }
    }
}

假设我是这样使用的:

function doSomething() {
    $tx = $this->txManager->beginTransaction();

    // ... code here may or may not throw an exception

    $tx->commit();
}

我能否 100% 确信在所有情况下(无论是否例外),析构函数将是函数结束后立即调用的第一个函数?

我的初始测试表明,是的,无论是否异常,都会立即调用析构函数。但我想要一个确认,最重要的是,一个指向相关文档的指针。

【问题讨论】:

  • 你读过PHP documentation about constructors and destructors吗?这是您可以获得的最相关的文档(除了 PHP 的源代码),它说:“只要没有对特定对象的其他引用,或者在关机顺序。”
  • 它(几乎)像在C++ 中一样保证被调用,而在Java 中,对象是垃圾回收的,并且不能保证析构函数被调用。
  • 只要是简单的异常(不是一些PHP扩展引起的crash),,保证调用析构函数为一旦对象超出范围(如果对象范围是函数并且在其他地方没有引用它,就是这种情况)。

标签: php destructor


【解决方案1】:

来自https://www.php.net/manual/en/language.oop5.decon.php#object.destruct

一旦没有对特定对象的其他引用,或在关闭序列期间以任何顺序调用,将立即调用析构函数。


在您的情况下,当任何地方都不再引用 $tx 时,就会发生这种情况。这将在我们处理完doSomething() 后立即执行,除非在txManager 中存储了另一个引用。

【讨论】:

  • 回到这个问题,我不知道将回滚放在析构函数中是否是您最好的方法。从文档中,它被称为“在关闭序列期间以任何顺序”。这意味着它也可以在数据库连接关闭之后调用。我不会依赖在析构函数中做这种事情。
  • 谢谢,我已经阅读了这个页面,但不知何故并没有说服我。在关闭序列期间关闭数据库连接的好处是,我想需要进行一些额外的检查以避免造成混乱。但是,在析构函数中进行回滚可以避免必须记住在整个事务性内容周围放置一个大的 try/catch
  • @Benjamin 您可以做的另一种方法是将事务函数作为参数传递。然后,您可以在您提交或回滚的地方使用 try catch 包装执行该参数函数。在 catch 函数中,您只需再次抛出异常以将其向上级联。伪示例:hastebin.com/utenovitar.php
  • 这正是我目前正在做的事情,但我发现它很麻烦,因为我每次都必须将许多变量绑定到闭包!
  • 是的,我知道随着时间的推移这会变得非常烦人
【解决方案2】:

当对象被破坏或脚本被破坏时调用一个析构函数 停止或退出。如果你创建一个 __destruct() 函数,PHP 将 在脚本结束时自动调用此函数。

DEMO

【讨论】:

    【解决方案3】:

    您可以使用register_shutdown_function PHP 代码完成后工作...

    
    <?php
    function shutdown()
    {
        // This is our shutdown function, in 
        // here we can do any last operations
        // before the script is complete.
    
        echo 'Script executed with success', PHP_EOL;
    }
    
    register_shutdown_function('shutdown');
    

    __desctruct 方法也是一个神奇的方法,当一个对象从内存中删除不需要调用它时,该方法自动工作

    【讨论】:

      猜你喜欢
      • 2019-04-07
      • 2015-09-23
      • 1970-01-01
      • 2019-11-15
      • 1970-01-01
      • 2020-11-05
      • 2018-05-09
      • 1970-01-01
      • 2013-06-20
      相关资源
      最近更新 更多