2010-03-05 2 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?

EDIT

Я выложу весь материал здесь, это тестирование среды 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__' –

+1

Или get_class ($ this); – Beachhouse

ответ

-4

Дону не знакомы с Доктриной, но проверьте одну точку: проверьте возможные исключения в __construct()/__ destruct(), они могут привести к фатальным ошибкам.

+1

Будет ли '_destruct' вызываться при возникновении фатальной ошибки? – user198729

+0

, если у вас есть фатальная ошибка, любое выполнение немедленно прекращается, поэтому трудно найти место, где оно произошло. –

+0

@SheinAlexey может быть трудно найти место, где это произошло? Это не верно. Парсер PHP точно покажет строку, число и причину этой ошибки. – Yang

13

Не имея выход на экране не означает, что деструктор не вызывается: ouptut может быть захвачено с использованием output_buffering (возможно, известь делает это, чтобы быть в состоянии работать на нем?), и не повторил, когда сценарий заканчивается, например.

Для тестирования вы можете попробовать написать файл в своем методе __destruct вместо того, чтобы просто повторять какой-либо текст.
(Просто убедитесь, что ваше приложение/PHP имеет необходимые привилегии для записи в файл назначения)

(я уже работать в ситуации, когда я не вижу выход, достигнутый в деструктор - но это было на самом деле называется)

+0

Насколько я знаю, даже соединения с базой данных закрываются при вызове __destruct. – TheHippo

+0

Я тестировал с 'file_put_contents', чтобы убедиться, что он не вызван. Но есть «PHP Fatal error» – user198729

+0

Что говорит Fatal Error? Означает ли это проблему в вашем скрипте или что-то не работает «как ожидалось»? –

65

__destruct будет не называться:

  • Если exit вызывается в другом destru т е р
  • В зависимости от версии PHP: если exit вызывается в функции отключения, зарегистрированной register_shutdown_function
  • Если есть фатальная ошибка где-то в коде
  • Если другой деструктор бросает исключение
  • Если вы пытаетесь обрабатывать исключение в деструкторе (PHP> = 5.3.0)

Guess, что все, что я могу думать прямо сейчас

& Что сказал Паскаль МАРТИН. Это первый шаг отладки.

+1

Я бы предположил, что PHP вводит «последовательность выключения» во всех этих случаях. См. Http://stackoverflow.com/questions/151660/php-destruct-method/8293937#8293937 для получения дополнительной информации. –

+0

Извините - я знаю, что это старый, но: Что делать, если процесс убит? – dgig

+5

@dgig Если процесс убит, процесс умирает. Его не спрашивают, нравится ли ему умирать, ему не дано время что-либо сделать, прежде чем он умрет, он просто мгновенно умирает. Так что нет, '__destruct()' также не выполняется. – Shi

9

Как the PHP documentation говорит:

Деструктор будет вызываться, даже если выполнение сценария остановлено с помощью exit(). Вызов exit() в деструкторе предотвратит выполнение остальных процедур выключения.

10

Метод __destruct также не будет вызываться, если скрипт выполняется на CLI и получает SIGTERM (Ctrl +C)

1

Я знаю I'am немного опоздал на вечеринку, но и для люди, которые также хотят получить __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 

Примечание: вызова выхода или исключения бросали в деструкторов или функции отключения заставит скрипт немедленно прекратить.

Смежные вопросы