2010-08-25 99 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