Php Destructors

时间:2010-08-25 13:13:11

标签: php destructor

当你必须在课堂上使用__destruct时,请给我一些真实的例子。

11 个答案:

答案 0 :(得分:42)

好的,因为我的上一个答案显然没有达到标准,让我再试一次。这个主题在互联网上有很多资源和例子。做一些搜索和浏览其他框架的代码,你会看到一些很好的例子......

不要忘记,仅仅因为PHP会在你终止时关闭资源并不意味着当你不再需要它们时显然关闭它们(或者好不关闭它们)...这取决于用例(它是否一直使用到最后,或者是早期有一个调用,然后在执行的其余部分时不再需要)...

现在,我们知道在销毁对象时会调用__destruct。从逻辑上讲,如果对象被销毁会发生什么?嗯,这意味着它已不再可用。因此,如果它有资源开放,那么关闭这些资源是否有意义,因为它被摧毁了?当然,在普通网页中,页面将很快终止,所以让PHP关闭它们通常并不可怕。但是,如果由于某种原因脚本长时间运行会发生什么?然后你有资源泄漏。那么,为什么不在不再需要时关闭所有内容(或者考虑析构函数的范围,当它不再可用时)?

以下是现实世界框架中的一些示例:

  1. Lithium's lithium\net\Socket class
  2. Kohana's Memcached Driver
  3. Joomla's FTP Implementation
  4. Zend Frameworks's SMTP Mail Transport Class
  5. CodeIgniter's TTemplate Class
  6. A Tidy Filter Helper for Cake
  7. A Google-Groups Thread about using Destructors For the Symfony Session Class
  8. 有趣的是,Kohana会跟踪标记,以便以后可以通过“命名空间”删除(而不是仅仅清除缓存)。因此它使用析构函数将这些更改刷新到硬存储。

    CodeIgniter类也做了一些有趣的事情,它将调试输出添加到析构函数中的输出流。我不是说这很好,但它是另一个用途的例子......

    每当我在主控制器上运行很长时间时,我个人都会使用析构函数。在构造函数中,我检查pid文件。如果该文件存在(并且其进程仍在运行),则抛出异常。如果没有,我创建一个包含当前进程ID的文件。然后,在析构函数中删除该文件。因此,除了释放资源之外,更多的是清理自己......

答案 1 :(得分:18)

还有另一个方便的用途来生成HTML页面

class HTMLgenerator {
  function __construct() {
    echo "<html><body>";
  }
  function __destruct() {
    echo "</body></html>";
  }
}

通过这门课,你可以写

$html = new HTMLgenerator();
echo "Hello, world!";

结果是

<html><body>Hello, world!</body></html>

答案 2 :(得分:6)

例如:

<?php
class Session
{
    protected $data = array();

    public function __construct()
    {
        // load session data from database or file
    }

    // get and set functions

    public function __destruct()
    {
        // store session data in database or file
    }
};

这是一个很好的使用destruct的原因。您可以始终阻止对会话源的读取和写入,并且仅在开始和结束时执行此操作。

答案 3 :(得分:4)

我创建了一个将生成电影信息jpg文件的php页面。此页面必须收集一些信息并运行inkscape将模板(svg文件)转换为png,然后再转换为jpg。 svg包含到其他图像的相对链接,该图像必须是文件。所以我的页面下载必要的文件到一个临时文件夹,转换svg文件。最后,必须删除临时文件夹。

我将临时文件夹删除到析构函数中。之前可能有很多原因导致页面意外结束,唯一的想法是我可以确定析构函数将在页面退出时调用。

希望这有帮助。

答案 4 :(得分:4)

如果使用自定义数据库连接器/包装器,析构函数非常有用。

在构造函数中,您可以传递连接信息。因为你可以使用析构函数(而不是终结器等),你可以依靠它来为你关闭连接。这更方便,但肯定有用。

例如,当PHP决定明确“释放”对象时(即,不再使用它),它将在那时调用析构函数。这在我描述的场景中更有用,因为您没有等待垃圾收集器运行并调用终结器。

$ 0.02

伊恩

答案 5 :(得分:4)

<?php
class Database
{
    private $connection;
    private $cache = array();

    function __construct([$params])
    {
        //Connection here
    }

    //Query
    public function query(Query $Query)
    {
        if($this->is_cached($Query->checksum))
        {
            return $this->get_cache($Query->checksum);
        }
        //...
    }
    public function __destruct()
    {
        unset($this->connection);
        $this->WriteCache();
        unset($this->cache);
        shutdown_log($this,'Destruction Completed');
    }
}
?>

这是一个让你明白的例子。

答案 6 :(得分:4)

如果您使用fopen()返回的句柄作为记录,则可以使用__destruct()确保在您的课程被销毁时在我们的资源上调用fclose()

答案 7 :(得分:4)

你说得对,__destruct对于短期运行的php脚本来说几乎是不必要的。数据库连接,文件句柄等在脚本退出时关闭,有时甚至更早,如果变量超出范围。

我能想到的一个例子是将日志写入数据库。由于我们不想在脚本中的某处创建每个日志条目的一个查询,因此我们在日志记录类的__destruct中编写了“write to db”部分,因此当脚本结束时,所有内容都会在一个数据库中插入数据库。

另一个例子:如果允许用户上传文件,析构函数有时候是删除临时文件的好地方(如果脚本出现问题,至少要清理它)

但即使是文件句柄也很有用。我已经开发了一个应用程序,它确实使用旧的fopen等调用包装在对象中,当在大型文件树上使用时,php迟早会用尽文件句柄,所以在脚本运行时清理不仅很好而且必要

答案 8 :(得分:3)

我对大量“低级”对象使用APC缓存,否则会使用过多的内存;我有一个cacheCollection对象,用于处理在执行脚本期间从APC读取和写入这些“低级”对象。当脚本终止时,必须从APC清除对象,因此我使用cacheCollection __destruct方法来执行该功能。

答案 9 :(得分:2)

我在包装数据库连接的日志记录类中使用了__destruct()

<?php

class anyWrap
{
  private $obj,$calls,$log,$hooks;
  function anyWrap($obj, $logfile = NULL)
  {
       if(is_null($logfile))
       {
         $this->log = dirname(__FILE__) . "/../logs/wrapLog.txt";
       }
       $this->hooks = array();
       $this->dbCalls = 0;
       $this->obj = $obj;
  }

   public function __set($attri, $val) {
       $this->obj->$attri = $val;
   }

   public function __get($attri) {      
       return $this->obj->$attri;
   }
  public function __hook($method)
  {
   $this->hooks[] = $method;
  }


   public function __call($name,$args)
   {
       $this->calls++;
       if(in_array($name,$this->hooks))
       {
           file_put_contents($this->log,var_export($args,TRUE)."\r\n",FILE_APPEND);
       }
       return call_user_func_array(array($this->obj,$name),$args);
   }
   //On destruction log diagnostics
   public function __destruct()
   {
        unset($this->dbReal);
        file_put_contents($this->log,$this->calls."\r\n",FILE_APPEND);
   }
}

脚本挂钩到数据库调用并记录prepare语句,然后当脚本运行结束时(我并不总是知道什么时候),它最终会将对数据库的调用次数记录到文件中。通过这种方式,我可以看到在数据库上调用了多少次函数并相应地规划了我的优化。

答案 10 :(得分:1)

如果您使用 MySQL 数据库中的PHP脚本创建视图,则必须在脚本末尾删除该视图。因为如果没有,则下次执行脚本时将不会创建视图,因为数据库中已存在类似名称的视图。为此,您可以使用析构函数。