Php破坏者
当你不得不在你的类中使用__destruct时,请给我一些真实的例子。
好的,因为我的最后一个答案显然没有达到标准,所以让我再试一次。 互联网上有很多关于这个话题的资源和例子。 做一些search和浏览其他框架的代码,你会看到一些很好的例子…
不要忘记,仅仅因为PHP会在你终止时closures资源并不意味着当你不再需要它们时closures它们是不好的(或者不要closures它们)。这取决于用例是直到最后使用,还是有一个电话,然后不需要再执行其余的执行)…
现在,我们知道__destruct
在对象被销毁时被调用。 从逻辑上讲,如果对象被销毁会发生什么? 那么,这意味着它不再可用。 因此,如果资源是开放的,在资源被破坏时closures这些资源是否合理? 当然,在普通的网页中,页面会在不久之后终止,所以让PHPclosures它们通常并不可怕。 但是,如果由于某种原因脚本长时间运行,会发生什么? 那么你有资源泄漏。 那么为什么不closures所有的东西呢?当你不再需要它时(或者考虑到析构函数的作用域,当它不再可用时)?
以下是真实世界框架中的一些示例:
- 锂电的锂\网\sockets类
- Kohana的Memcached驱动程序
- Joomla的FTP实现
- Zend框架的SMTP邮件传输类
- CodeIgniter的TTemplate类
- 一个整洁的蛋糕filter帮手
- 关于使用析构函数的Google-Groups主题对于Symfony会话类
有趣的是Kohana会跟踪标签,以便稍后可以通过“名称空间”删除它(而不仅仅是清除caching)。 所以它使用析构函数将这些更改刷新到硬存储中。
CodeIgniter类也做了一些有趣的事情,它将debugging输出添加到析构函数的输出stream中。 我不是说这很好,但是这是另一个用途的例子。
我个人使用析构函数,只要我在主控制器上长时间运行进程。 在构造函数中,我检查一个pid
文件。 如果该文件存在(并且其进程仍在运行),则会抛出exception。 如果没有,我用当前进程ID创build一个文件。 然后,在析构函数中删除该文件。 所以它更多的是清理自己而不是释放资源。
还有一个方便的用途来生成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>
例如:
<?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 } };
这是一个很好的为什么使用破坏。 您一直阻止读取和写入会话源,只在开始和结束时执行此操作。
我创build一个php页面会产生一个电影信息jpg文件。 这个页面将不得不收集一些信息,并运行inkscape将模板(一个SVG文件)转换为PNG之前,转换为JPG格式。 svg包含相对于其他图片的链接,它必须是一个文件。 所以我的网页下载必要的文件到一个临时文件夹中,转换成svg文件。 最后,临时文件夹必须被删除。
我把临时文件夹删除到析构函数中。 在页面结束之前,可能有许多原因,只有当我们可以肯定的是析构函数会在页面退出时调用。
希望这可以帮助。
如果使用自定义数据库连接器/包装器,析构函数是非常有用的。
在构造函数中,可以传递连接信息。 因为可以使用析构函数(而不是终结器等),所以可以依靠它来closures连接。 这更方便,但肯定是有用的。
例如,当PHP决定明确“释放”对象(即不再使用它)时,它将在那个时候调用析构函数。 这在我描述的场景中更有用,因为您不等待垃圾收集器运行并调用终结器。
$ 0.02
伊恩
如果使用fopen()
返回的句柄进行日志logging,则可以使用__destruct()
来确保在您的类被销毁时在我们的资源上调用fclose()
。
你是对的, __destruct
是短期运行的PHP脚本是不必要的。 数据库连接,文件句柄等closures脚本退出或有时甚至更早如果variables超出范围。
我能想到的一个例子是将日志写入数据库。 由于我们不希望在脚本中创build每个日志条目,因此我们在日志logging类的__destruct中写入了“写入数据库”部分,因此当脚本结束时,所有内容都将被插入到数据库中。
另一个例子:如果你允许用户上传文件,析构函数有时是删除临时文件的好地方(如果脚本出错了,至less要清理掉)
但是即使是文件句柄也是有用的。 我曾经在一个应用程序中使用过打包在对象中的旧的fopen等调用,当在大型文件树中使用这些调用时,php迟早会用完文件句柄,因此脚本运行时的清理不仅是好的,而且是必要的。
我使用APCcaching大量“低级”对象,否则会使用过多的内存; 而且我有一个cacheCollection对象,用于在脚本执行期间处理从APC读写这些“低级”对象。 当脚本终止时,必须从APC清除对象,所以我使用cacheCollection __destruct方法来执行该function。
<?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'); } } ?>
这是一个应该让你明白的例子。
我在包装数据库连接的日志logging类中使用了__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); } }
脚本挂钩到数据库调用并logging准备语句,然后当脚本运行结束(我不知道什么时候),它会最终logging调用数据库的次数到文件。 这样我可以看到某些函数在数据库上被调用了多less次,并据此计划我的优化。
如果您在MySQL数据库中使用PHP脚本创build视图 ,则必须在脚本结尾处删除该视图。 因为如果没有,那么下次执行脚本的视图将不会被创build,因为数据库中已经有了一个类似名称的视图。 为此,您可以使用析构函数。