web-dev-qa-db-ja.com

PHPで__destructが呼び出されないのはいつですか?

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

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

$obj = new MyDestructableClass();

上記のスクリプトがcomplex環境にある場合、__destructexitのときに呼び出されませんが、簡単に再現することはできません。これに気づいた人はいますか?

[〜#〜]編集[〜#〜]

すべてをここに投稿します。これは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();
50
user198729

__destructnotが呼び出されます:

  • exitが別のデストラクタで呼び出された場合
  • PHP Versionに依存:exitregister_shutdown_functionで登録されたシャットダウン関数で呼び出された場合
  • コードのどこかに致命的なエラーがある場合
  • 別のデストラクタが例外をスローした場合
  • デストラクタで例外を処理しようとした場合(PHP> = 5.3.0)

今考えられるのはそれだけです

&パスカル・マーティンが言ったこと。これがデバッグの最初のステップです。

71
edorian

画面に出力がなくても、デストラクタが呼び出されないわけではありません。出力は、output_bufferingを使用してキャプチャできます(おそらくLimeがそれを処理できるようにするために、)エコーされません。たとえば、スクリプトが終了したとき。

テストの目的で、__destructメソッド。テキストをエコーするだけではありません。
(アプリケーションに注意してください/ PHP宛先ファイルに書き込むために必要な権限がある)

(デストラクタで作成された出力が表示されない状況にすでに遭遇しています-しかし、実際には呼び出されました)

14
Pascal MARTIN

__destructメソッドは、CLIでスクリプトが実行されていてSIGTERM(Ctrl+C

12
nickel715

the PHP documentation は言う:

デストラクタは、exit()を使用してスクリプトの実行が停止された場合でも呼び出されます。デストラクタでexit()を呼び出すと、残りのシャットダウンルーチンが実行されなくなります。

11

私はパーティーに少し遅れていることを知っていますが、__destruct実行する CTRL+C 致命的なエラーが発生した場合は、これを試すことができます(以下はテストケースです)。

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を呼び出すか、デストラクタまたはシャットダウン関数で例外をスローすると、スクリプトがすぐに終了します。

3
WhiteFang