什么时候 __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
When will __destruct not be called in PHP?
提问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 withregister_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(). Callingexit()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):
我知道我参加聚会有点晚了,但对于那些也希望__destruct在CTRL+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() 中可能的异常,它们会产生致命错误。

