【问题标题】:How to destroy an object?如何销毁一个对象?
【发布时间】:2012-02-06 13:54:27
【问题描述】:

据我所知(很少),有两种方法:

$var = new object()

然后:

// Method 1: Set to null
$var = null;
// Method 2: Unset 
unset($var); 

其他更好的方法?我在这扯头发吗?

【问题讨论】:

    标签: php object destructor destroy


    【解决方案1】:

    您正在寻找unset()

    但请注意,您不能明确销毁对象。

    它将保留在那里,但是如果您取消设置对象并且您的脚本将 PHP 推送到内存限制,则不需要的对象将被垃圾收集。我会选择unset()(而不是将其设置为null),因为它似乎具有更好的性能(未经测试,但记录在PHP官方手册的one of the comments中)。

    也就是说,请记住 PHP 总是会在页面被提供后立即销毁对象。因此,只有在非常长的循环和/或大量密集页面上才需要这样做。

    【讨论】:

    • 所以弗兰基,我来自 C++,当我们使用一次 new 时,我们必须使用一次 delete。这在 PHP 中不是真的吗?不再需要对象时有自动垃圾回收吗?
    • @gsamaras 这是真的。但是,您也可能有泄漏,如果您正在使用守护程序或类似的东西,您应该阅读更多关于 php 的 GC 的内容。在大多数站点中,请求的生命周期都很短,因此无关紧要。 php.net/manual/en/features.gc.refcounting-basics.php
    • unset() 是否删除了对 Object 的引用?
    • 这个答案在 2021 年仍然有效吗?它是 UnitTesting 所必需的,我认为这个概念在 2012 年传播得并不远
    【解决方案2】:

    一个方便的帖子解释了对此的几个误解:

    Don't Call The Destructor explicitly

    这涵盖了关于析构函数如何工作的几个误解。根据 PHP5 文档,显式调用它实际上不会破坏您的变量:

    PHP 5 引入了与其他类似的析构函数概念 面向对象的语言,例如 C++。析构方法将是 一旦没有其他对特定的引用就调用 对象,或在关闭序列期间以任何顺序。

    上面的帖子确实指出,在某些情况下将变量设置为 null 可以工作,只要没有其他内容指向分配的内存。

    【讨论】:

      【解决方案3】:

      简答:两者都需要。

      我觉得给出了正确的答案,但很少。是的,通常 unset() 最适合“速度”,但如果你想立即回收内存(以 CPU 为代价)应该使用 null。

      像其他人提到的那样,设置为 null 并不意味着一切都被回收,您可以拥有共享内存(未克隆)对象,以防止对象被破坏。此外,就像其他人所说的那样,无论如何您都不能明确地“销毁”对象,因此无论如何您都不应该尝试这样做。

      您需要找出最适合您的方法。您也可以将 __destruct() 用于将在 unset 或 null 上调用的对象,但应谨慎使用,就像其他人所说的那样,永远不要直接调用!

      见:

      http://www.stoimen.com/blog/2011/11/14/php-dont-call-the-destructor-explicitly/

      What is difference between assigning NULL and unset?

      【讨论】:

        【解决方案4】:

        可能是在您正在创建新的 mysqli 对象的情况下。

        $MyConnection = new mysqli($hn, $un, $pw, $db);

        但即使你关闭了对象

        $MyConnection->close();

        如果你使用print_r()来检查$MyConnection的内容,你会得到如下错误:

        Error:
        mysqli Object
        
        Warning: print_r(): Property access is not allowed yet in /path/to/program on line ..
        ( [affected_rows] => [client_info] => [client_version] =>.................)
        

        在这种情况下,您不能使用unlink(),因为unlink() 需要一个路径名字符串,但在这种情况下$MyConnection 是一个对象。

        因此,您可以选择将其值设置为 null:

        $MyConnection = null;

        现在一切顺利,正如您所料。您在变量 $MyConnection 中没有任何内容,并且您已经清理了 mysqli 对象。

        建议在将变量的值设置为 null 之前关闭对象。

        【讨论】:

          【解决方案5】:

          在 PHP 中,您不是在销毁对象,而是在销毁指向该对象的指针。差别很大。

          在其他语言中,您可以销毁一个对象,所有其他指针都会给您异常或垃圾,但对于 PHP,情况并非如此。

          这是一个简单的证明,你不能破坏一个对象,你只能破坏一个指向它的链接。

          $var = (object)['a'=>1];
          $var2 = $var;
          $var2->a = 2;
          unset($var2);
          echo $var->a;
          

          返回

          2

          在此处查看实际操作:https://eval.in/1054130

          【讨论】:

          • 对,你已经销毁了 $var2,它是对 $var 的引用。现在你也销毁$var,并且假设没有其他引用持有该对象,你就完成了。
          • 您不是在销毁一个对象,而是在销毁一个指向该对象的指针。这是一个很大的不同。
          • 在其他语言中,您可以销毁一个对象,所有其他指针都会给您异常或垃圾,但对于 php,情况并非如此
          • 你不能破坏。如果没有引用持有该对象,则该对象已准备好被垃圾收集器收集。而且你不能强制运行垃圾收集器。
          【解决方案6】:

          我会选择 unset ,因为它可能会给垃圾收集器一个更好的提示,以便内存可以更快地再次可用。请注意,对象指向的任何东西要么有其他引用,要么首先取消设置,否则你真的必须等待垃圾收集器,因为这样就没有它们的句柄了。

          【讨论】:

          • 除非您确实有资源来支持您的答案,否则您可能不应该发布您认为“可能”发生的事情。它没有用,并导致这种错误信息被视为事实并重复。
          • @meagar 这就是我链接到官方手册页的确切原因,在 cmets 中,有一个将 unset() 与 null 进行比较的示例测试。
          猜你喜欢
          • 2017-06-29
          • 1970-01-01
          • 1970-01-01
          • 2012-07-09
          • 2012-05-02
          • 2015-02-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多