首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >重用对象不会调用`__destruct`吗?

重用对象不会调用`__destruct`吗?
EN

Stack Overflow用户
提问于 2019-12-25 14:41:14
回答 1查看 51关注 0票数 1

我试图在CLI程序中建立一个类似于“池”的结构,其中包括大量的“借款”和“回收”。在测试的过程中,我遇到了一些意想不到的事情:

代码语言:javascript
复制
<?php
class FOO
{
    public static $pool=[];
    public static function get()
    {
        if(empty(self::$pool))
        {
            self::$pool[]=new self(mt_rand(1000,9999));
        }
        return array_shift(self::$pool);
    }
    protected static function recycle(FOO $foo)
    {
        echo "Recycling {$foo->num}\n";
        self::$pool[]=$foo;
    }

    public $num;
    protected function __construct(int $num)
    {
        $this->num=$num;
    }
    public function __destruct()
    {
        static::recycle($this);
    }
}
function Bar()
{
    $foo=FOO::get();
    echo "Got {$foo->num}\n";
}
echo "Bar\n";
Bar();
echo "Bar\n";
Bar();
echo "Bar\n";
Bar();
echo "Bar\n";
Bar();
print_r(FOO::$pool);
echo "End.\n";

产出如下:

代码语言:javascript
复制
Bar
Got 2911
Recycling 2911
Bar
Got 2911
Bar
Got 1038
Recycling 1038
Bar
Got 1038
Array
(
)
End.

如果将Bar()调用限制为3次而不是4次,则得到以下输出:

代码语言:javascript
复制
Bar
Got 7278
Recycling 7278
Bar
Got 7278
Bar
Got 6703
Recycling 6703
Array
(
    [0] => FOO Object
        (
            [num] => 6703
        )

)
End.

在这里您可以看到,当一个对象被“重用”时(参见示例1,7278中的2911和1038 ),它的__destruct()将不会被调用;相反,它将简单地消失。

我很困惑。为什么会发生这种事?为什么每次都不给FOO->__destruct打电话?是否有可能使FOO自动回收自身的实例?

我正在PHP-7.2中测试这一点,这是在Windows和WSL中都可以观察到的行为。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-12-25 15:41:15

据我所知,对于同一个对象,析构函数不会被调用两次。从析构函数中重用对象通常是一种不好的做法。应该销毁而不是重用其析构函数的对象。在您的测试脚本中,它不会引起任何严重的问题,但是在现实生活中,如果开发人员不小心,这种使用可能会导致意想不到的行为。

起初,当我读到你的问题时,我担心你造成了内存泄漏,但事实并非如此。当您离开Bar()的作用域时,析构函数才会被调用,只有在这个对象上还没有调用它的时候。但是,由于保存引用并在ref_count中增加该对象的__destruct(),垃圾收集器还不能收集对象。它必须等到下一次当您减少这个对象的ref_count时。

这一过程可解释如下(简化):

  1. ,您称之为Bar()函数,它创建FOO的一个实例。创建一个对象并将其分配给$foo。(ref_count = 1)
  2. --在Bar()的末尾--唯一对该对象的引用丢失(ref_count = 0),这意味着PHP启动了销毁对象的过程。

2.1。破坏者被称为。在析构函数中,将ref_count增加到1。

2.2。下一步是GC收集对象,但ref_count不是零。这可能意味着一个循环,或者在您的示例中,已经在析构函数中创建了一个新的引用。GC必须等待,直到没有非周期引用来收集对象。你又叫

  • Bar()。您将相同的对象从静态数组中移除,这意味着FOO::$pool中的引用消失了,但您立即将其分配给$foo。(ref_count = 1)

  • Upon -- Bar()的末尾--对这个对象的唯一引用丢失了(ref_count = 0),这意味着GC最终可以收集这个对象。析构函数已经被调用,因此这里没有其他的操作。

您没有回收对象,您只是延长了它在内存中的存在。您可以再访问它一段时间,但是对于PHP,该对象已经在被销毁的过程中。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59479395

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档