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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2385047/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 06:16:16  来源:igfitidea点击:

When will __destruct not be called in PHP?

phpdestructor

提问by user198729

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

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

$obj = new MyDestructableClass();

When the above script is in a complexenvironment,the __destructwon't get called when exit,but I can't reproduce it easily.Have someone ever noticed this ?

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

EDIT

编辑

I'll post the whole stuff here,it's the testing environment of symfony,which means you can easily reproduce it if you are familar with the framework:

我把所有的东西都贴在这里,它是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();

回答by edorian

The __destructwill notbe called:

__destruct不会被调用:

  • If exitis called in another destructor
  • Depending on the PHP Version: if exitis called in a shutdown function registered with register_shutdown_function
  • If there is a fatal error somewhere in the code
  • If another destructor throws an exception
  • If you try to handle an exception in a destructor (PHP >= 5.3.0)
  • 如果exit在另一个析构函数中调用
  • 取决于 PHP 版本:如果exit在注册的关闭函数中调用register_shutdown_function
  • 如果代码中某处有致命错误
  • 如果另一个析构函数抛出异常
  • 如果您尝试在析构函数中处理异常 (PHP >= 5.3.0)

Guess that's all I can think of right now

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

& What Pascal MARTIN said. That's the first step of debugging that.

& 帕斯卡·马丁 (Pascal MARTIN) 所说的话。这是调试它的第一步。

回答by nickel715

The __destructmethod will also not be called if script is running on CLI and receives a SIGTERM (Ctrl+C)

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

回答by Pascal MARTIN

Not having an output on the screen doesn't mean the destructor is not called : the ouptut could be captured using output_buffering (maybe lime does that, to be able to work on it ? ), and not echoed when the script ends, for instance.

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

For testing purposes, you could try writing to a file, in your __destructmethod, instead of just echoing some text.
(Just make sure your application / PHP has the required privileges to write to your destination file)

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

(I've already run into situations where I would not see the output made in a destructor -- but it was actually called)

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

回答by Arek - Krakiewicz.pl

As the PHP documentationsays:

正如PHP 文档所说:

The destructor will be called even if script execution is stopped using exit(). Calling exit()in a destructor will prevent the remaining shutdown routines from executing.

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

回答by WhiteFang

I know I'am a little late to the party but for people who are also looking to get __destructto be executed when CTRL+Cand/or Fatal errors occur, you can try this (below is a test case):

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

Index.php

索引.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

Note:calling exit or throwing exceptions in destructors or shutdown functions will cause the script to terminate immediately.

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

回答by Alexey Shein

Don't familiar with the Doctrine, but check one point: check for possible exceptions in __construct()/__destruct() they can produce fatal errors.

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