什么时候不会在PHP中调用__destruct?

use*_*729 49 php destructor

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

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

$obj = new MyDestructableClass();
Run Code Online (Sandbox Code Playgroud)

当上面的脚本处于复杂的环境中时,__destruct不会被调用exit,但是我无法轻易地重现它.有人注意到了吗?

编辑

我将在这里发布所有内容,它是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();
Run Code Online (Sandbox Code Playgroud)

edo*_*ian 71

__destruct不会被调用:

  • 如果exit在另一个析构函数中调用
  • 取决于PHP版本:if exit在注册的shutdown函数中调用register_shutdown_function
  • 如果代码中某处出现致命错误
  • 如果另一个析构函数抛出异常
  • 如果您尝试在析构函数中处理异常(PHP> = 5.3.0)

猜猜这就是我现在所能想到的

帕斯卡尔马丁说的是什么.这是调试的第一步.

  • @dgig如果进程被终止,进程就会死掉.不要问它是否喜欢死,没有时间去做任何事情,它会死亡,它只会立即死亡.所以不,那么`__destruct()`也没有被执行. (5认同)

Pas*_*TIN 14

屏幕上没有输出并不意味着没有调用析构函数:可以使用output_buffering捕获ouptut (也许是石灰会这样做,能够对它进行处理吗?),而不是在脚本结束时回显,例如.

出于测试目的,您可以尝试在__destruct方法中写入文件,而不是仅回显一些文本.
(只需确保您的应用程序/ PHP具有写入目标文件所需的权限)

(我已经遇到过我不会在析构函数中看到输出的情况 - 但它实际上被调用了)


nic*_*715 13

__destruct如果脚本在CLI上运行并且收到SIGTERM(Ctrl+ C),则也不会调用该方法

  • 需要澄清的是, <kbd>Ctrl</kbd>+<kbd>C</kbd> 通常发送 `SIGINT` 信号(而不是 SIGTERM)。但确实在这种情况下也不会调用`__destruct`。 (2认同)

Are*_*.pl 11

正如PHP文档所说:

即使使用停止脚本执行,也将调用析构函数exit().调用exit()析构函数将阻止执行剩余的关闭例程.


Whi*_*ang 5

我知道我参加聚会有点晚了,但对于那些也希望__destructCTRL+C和/或致命错误发生时被处决的人,您可以试试这个(下面是一个测试用例):

索引.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');
Run Code Online (Sandbox Code Playgroud)

测试文件

<?php

// this will create a parse (E_PARSE) error.
asdsaddsaadsasd
Run Code Online (Sandbox Code Playgroud)

注意:在析构函数或关闭函数中调用 exit 或抛出异常将导致脚本立即终止。


Ale*_*ein -4

不熟悉该原则,但请检查一点:检查 __construct()/__destruct() 中可能存在的异常,它们可能会产生致命错误。