2010-08-25 100 views
53

当你不得不在你的类中使用__destruct时,请给我一些真实的例子。Php破坏者

+23

为什么收盘票?问题不是那么可怕的IMO:它要求真实世界的使用,其中有许多PHP中没有*,因为大多数资源和连接都会自动关闭。 – 2010-08-25 13:18:18

+2

这个问题应该标记为社区维基 – tamasd 2010-08-25 13:49:22

+2

我投票赞成Pekka,我投了赞成daniphp,并标记为最喜欢的问题,只因为我认为Yorirou是错误的:) – RobertPitt 2010-08-25 14:08:20

回答

38

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

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

现在,我们知道__destruct在对象被销毁时被调用。从逻辑上讲,如果物体被破坏会发生什么?那意味着它不再可用。因此,如果资源开放,那么在资源被破坏时关闭这些资源是否合理?当然,在普通的网页中,页面会在不久之后终止,所以让PHP关闭它们通常并不可怕。但是,如果由于某种原因脚本长时间运行会发生什么?然后你有资源泄漏。那么,为什么不在需要的时候关闭所有的东西?(或者考虑到析构函数的作用域,当它不再可用时)?

下面是一些例子在现实世界中的框架:

  1. Lithium's lithium\net\Socket class
  2. Kohana's Memcached Driver
  3. Joomla's FTP Implementation
  4. CodeIgniter's TTemplate Class
  5. A Tidy Filter Helper for Cake
  6. A Google-Groups Thread about using Destructors For the Symfony Session Class

有趣的是,Kohana的跟踪标签,所以它可以通过“命名空间”后(而不仅仅是清除缓存)删除。所以它使用析构函数将这些更改清除到硬存储中。

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

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

+2

非常好的工作。 +1 – 2010-08-25 13:54:05

+0

喜欢这个涵盖了这么多已知PHP软件的链接列表。 – markus 2011-03-03 21:44:04

+0

用例的完整列表+1 – 2011-04-06 18:37:19

4

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

我把临时文件夹删除到析构函数中。在页面结束之前可能有很多原因,并且唯一能想到的就是当页面退出时析构函数会被调用。

希望这会有所帮助。

3

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

+0

你在开玩笑我 - downvote提供一个我自己的用法的真实生活的例子,当这就是问题的要求?你可能会认为这是一种不恰当的用法,但它绝对是“野外”的真实生活用法,这正是OP所要求的。 – 2013-05-03 15:18:25

4

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

在构造函数中,可以传递连接信息。因为可以使用析构函数(而不是终结器等),所以可以依靠它来关闭连接。这更方便,但它确实很有用。例如,当PHP决定明确地“释放”该对象(即不再使用它)时,它将在那时调用析构函数。这在我描述的场景中更有用,因为您不等待垃圾收集器运行并调用终结器。

$ 0.02

伊恩

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'); 
    } 
} 
?> 

那里有一个例子,应该让你明白。

4

如果您使用fopen()的发言权,记录返回的句柄,你可以使用__destruct()确保fclose()被称为我们的资源,当你的类被破坏。

4

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

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

又如:如果您允许用户上传文件的析构函数有时是一个不错的地方,删除临时文件(万一出错脚本它至少得到清理)

但即使是文件句柄可以是有用的。我已经开发了一个应用程序,它使用包装在对象中的旧fopen等调用,并且在大型文件树上使用这些调用时,php早晚会耗尽文件句柄,因此脚本运行时的清理不仅很好,而且也是必需的。

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); 
    } 
} 

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

1

如果你正在使用的MySQL的数据库 PHP脚本创建视图,则必须下降这种看法在脚本的结尾。因为如果没有,下次执行该脚本视图将不会被创建,因为数据库中已经有一个类似名称的视图。为此,您可以使用析构函数。

+1

假设您指的是数据库视图,为什么要在每个执行周期创建它(并在每次运行后删除它)?为什么不一次创建它并将其留在那里?作为他们的一个规则,生产代码不应该以“CREATE”或“DROP”特权运行,而应该单独按照每个请求来执行......或者我误解了你的意思? (否则它是一个析构函数的有效例子,所以没有-1)... – ircmaxell 2010-08-25 17:43:09

5

例如:

<?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 
    } 
}; 

这是一个很好为什么要使用自毁。您可以始终防止对会话源进行读取和写入,并且只在开始和结束时执行此操作。

17

还有一个方便的使用,以生成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> 
+8

我不认为这应该在现实世界中使用,看起来像一个黑客。依赖于一个非常具体的用法。我只是将HTMLgenerator实现为在其构造函数中使用一些HTML,并覆盖toString方法。调用者可以简单地说'echo new HTMLGenerator()'。如果你使用这个_destructor回声模式,你最好只在一个地方使用它,否则你将会试图弄清楚什么时候会输出。总之,这是一个功能的滥用。 – 2011-01-18 21:13:50

+0

我同意。这只是一个想法,它可能会引发一些聪明的想法,所以让这个外部生活:-) – 2011-01-18 21:41:10