2010-03-05 76 views
47
class MyDestructableClass { 
    function __construct() { 
     print "\nIn constructor\n"; 
     $this->name = "MyDestructableClass"; 
    } 

    function __destruct() { 
     print "\nDestroying " . $this->name . "\n"; 
    } 
} 

$obj = new MyDestructableClass(); 

當上面的腳本是在複雜環境下,__destruct不會被調用時exit,但我不能複製easily.Have有人注意過這個?什麼時候__destruct不會在PHP中被調用?

編輯

我會在這裏張貼整個的東西,這是symfony中的測試環境,這意味着你可以很容易地複製它,如果您熟悉的框架:

require_once dirname(__FILE__).'/../bootstrap/Doctrine.php'; 


$profiler = new Doctrine_Connection_Profiler(); 

$conn = Doctrine_Manager::connection(); 
$conn->setListener($profiler); 

$t = new lime_test(0, new lime_output_color()); 

class MyDestructableClass { 
    function __construct() { 
     print "\nIn constructor\n"; 
     $this->name = "MyDestructableClass"; 
    } 

    function __destruct() { 
     print "\nDestroying " . $this->name . "\n"; 
    } 
} 

$obj = new MyDestructableClass(); 
$news = new News(); 

$news->setUrl('http://test'); 
$news->setHash('http://test'); 
$news->setTitle('http://test'); 
$news->setSummarize('http://test'); 
$news->setAccountId(1); 
$news->setCategoryId(1); 
$news->setThumbnail('http://test'); 
$news->setCreatedAt(date('Y-m-d H:i:s',time())); 
$news->setUpdatedAt(date('Y-m-d H:i:s',time())); 
$news->save(); 
exit(); 
+11

與您的問題無關,但$ this-> name是不必要的 - 而是使用特殊常量'__CLASS__' – 2010-03-05 06:59:43

+1

或get_class($ this); – Beachhouse 2015-01-29 16:17:16

回答

-4

唐不熟悉Doctrine,但請檢查一點:檢查__construct()/ __ destruct()中可能出現的異常,它們可能會產生致命錯誤。

+1

當有致命錯誤時,會調用'_destruct'嗎? – user198729 2010-03-05 08:11:48

+0

如果你有致命的錯誤,任何執行立即停止,所以它可能很難找到它發生的地方。 – 2010-03-06 11:50:45

+0

@SheinAlexey可能很難找到它發生的地方?這是錯誤的。 PHP解析器將顯示該錯誤的行,數量和原因。 – Yang 2013-01-02 01:58:55

13

不具有屏幕上的輸出並不意味着析構函數不叫:該ouptut可以使用output_buffering 被捕獲(也許石灰這樣做,才能夠進行這項工作?),並沒有呼應時腳本結束,例如。

出於測試目的,您可以嘗試寫入文件,在您的__destruct方法中,而不是僅回顯一些文本。
(只要確保你的應用程序/ PHP具有所需的權限來寫你的目標文件)

(我已經運行到哪裏,我不會看到在析構函數進行的輸出的情況 - 但是它實際上是所謂的)

+0

據我所知即使數據庫連接已關閉__destruct被調用時。 – TheHippo 2010-03-05 08:03:26

+0

我用'file_put_contents'測試過,以確保它不被調用。但有一個'PHP致命錯誤' – user198729 2010-03-05 08:12:14

+0

致命錯誤說什麼?它是否表明您的腳本中存在問題,或者是否「按預期」工作? – 2010-03-05 11:14:31

65

__destruct被稱爲:

  • 如果exit被稱爲在另一個destru構造函數
  • 根據PHP版本:如果exit被稱爲與register_shutdown_function
  • 註冊的關機功能。如果有一個致命的錯誤某處代碼
  • 如果如果你嘗試另一個析構函數拋出異常
  • 在析構函數處理異常(PHP> = 5.3.0)

想這是所有我能想到的,現在

&帕斯卡爾馬丁說什麼。這是調試的第一步。

+1

我猜想PHP在所有這些情況下都會輸入「關閉順序」。有關更多信息,請參閱http://stackoverflow.com/questions/151660/php-destruct-method/8293937#8293937。 – 2013-05-07 11:52:19

+0

對不起 - 我知道這是舊的,但:如果這個過程被殺死了怎麼辦? – dgig 2014-05-05 21:04:08

+5

@dgig如果進程被終止,進程就會死亡。人們並沒有問它是否喜歡死亡,在死亡之前沒有時間做任何事情,它只是立即死亡。所以不,'__destruct()'也不會被執行。 – Shi 2014-06-09 14:32:21

9

由於the PHP documentation說:即使腳本執行使用exit()停止

析構函數將被調用。在析構函數中調用exit()將會阻止執行其餘的關閉例程。

10

__destruct方法也不會被如果腳本在CLI運行打來電話,收到SIGTERM(按Ctrl +Ç

1

我知道我'有點遲到了但人誰也希望得到__destruct被執行時CTRL +ç /或出現致命錯誤,你可以試試這個(下面是一個測試用例):

的index.php

<?php 

// Setup CTRL+C and System kill message handler 
// The only signal that cannot be caught is the SIGKILL (very hard kill) 
declare(ticks = 1); // Required else it won't work. 
pcntl_signal(SIGTERM, 'close'); // System kill (Unhappy Termination) 
pcntl_signal(SIGINT, 'close'); // CTRL+C (Happy Termination) 

// Shutdown functions will be executed even on fatal errors 
register_shutdown_function('close'); 

function close($signal = null) // only pcntl_signal fills $signal so null is required 
{ 
    // Check if there was an fatal error (else code below isn't needed) 
    $err = error_get_last(); 
    if(is_array($err)) 
    { 
     foreach(array_keys($GLOBALS) as $key) 
     { 
      if(in_array($key, ['_GET', '_POST', '_COOKIE', '_FILES', '_SERVER', '_REQUEST', '_ENV', 'GLOBALS'])) 
       continue; 

      // This will automatically call __destruct 
      unset($GLOBALS[$key]); 
     } 
    } 
} 

// Example 
class blah 
{ 
    private $id = ''; 

    public function __construct() 
    { 
     $this->id = uniqid(); 
     // note this piece of code, doesn't work on windows! 
     exec('mkdir /tmp/test_'.$this->id); 
    } 

    public function __destruct() 
    { 
     // note this piece of code, doesn't work on windows! 
     exec('rm /tmp/test_'.$this->id.' -R'); 
    } 
} 

// Test 
$a = new blah(); 
$b = new blah(); 
$c = new blah(); 
$d = new blah(); 
$e = new blah(); 
$f = new blah(); 
$g = new blah(); 
$h = new blah(); 
$i = new blah(); 
$j = new blah(); 
$k = new blah(); 
$l = new blah(); 
$m = new blah(); 
$n = new blah(); 
$o = new blah(); 
$p = new blah(); 
$q = new blah(); 
$r = new blah(); 
$s = new blah(); 
$t = new blah(); 
$u = new blah(); 
$v = new blah(); 
$w = new blah(); 
$x = new blah(); 
$y = new blah(); 
$z = new blah(); 

// The script that causes an fatal error 
require_once(__DIR__.'/test.php'); 

test.php的

<?php 

// this will create a parse (E_PARSE) error. 
asdsaddsaadsasd 

注:調用exit或析構函數或關機等功能拋出異常會導致腳本立即終止。

相關問題