2010-03-05 13 views
47
class MyDestructableClass { 
    function __construct() { 
     print "\nIn constructor\n"; 
     $this->name = "MyDestructableClass"; 
    } 

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

$obj = new MyDestructableClass(); 

Cuando la secuencia de comandos se encuentra en un complejo entorno , la __destruct no se llamará cuando exit, pero no puedo reproducirlo easily.Have alguna vez alguien se dio cuenta de esto?¿Cuándo __destruct no se llamará en PHP?

EDITAR

voy a publicar todo el material aquí, es el entorno de pruebas de Symfony, que significa que puede reproducir fácilmente si está familiarizado con el marco:

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

No relacionado con su pregunta, pero $ this-> name no es necesario; en su lugar, use la constante especial '__CLASS__' –

+1

O get_class ($ this); – Beachhouse

Respuesta

-4

Don Está familiarizado con la Doctrina, pero verifique un punto: verifique las posibles excepciones en __construct()/__ destruct() pueden producir errores fatales.

+1

¿Se llamará a '_destruct' cuando hay un error fatal? – user198729

+0

si tiene un error fatal, cualquier ejecución se detiene inmediatamente, por lo que puede ser difícil encontrar el lugar donde sucedió. –

+0

@SheinAlexey puede ser difícil encontrar el lugar donde sucedió? Esto está mal. El analizador de PHP mostrará exactamente la línea, el número y el motivo de ese error. – Yang

13

No tener una salida en la pantalla no significa que el destructor no se llama: el ouptut podría ser capturado utilizando output_buffering (tal vez la cal hace que, para ser capaz de trabajar en él?), y no se hizo eco cuando el guion termina, por ejemplo.

Para fines de prueba, podría intentar escribir en un archivo, en su método __destruct, en lugar de simplemente hacer eco de algún texto.
(Sólo asegúrese de que su aplicación/PHP tiene los privilegios necesarios para escribir en el archivo de destino)

(yo ya he encontrado con situaciones en las que no vería la salida hecha en un destructor - pero que en realidad se llamaba)

+0

Hasta donde yo sé, incluso las conexiones de la base de datos están cerradas cuando se llama a __destruct. – TheHippo

+0

Probé con 'file_put_contents' para asegurarme de que no se invocó. Pero hay un 'Error fatal de PHP' – user198729

+0

¿Qué dice el error fatal? ¿Indica un problema en su script, o algo que no funciona "como se esperaba"? –

65

El __destruct se no ser llamados:

  • Si exit se llama en otro destru Héctor
  • dependiendo de la versión de PHP: si exit se llama en una función de desconexión registrado en register_shutdown_function
  • Si hay un error fatal en algún lugar del código
  • Si otro destructor lanza una excepción
  • Si intenta manejar una excepción en un destructor (PHP> = 5.3.0)

supongo que eso es todo lo que puedo pensar ahora mismo

& Lo que dijo Pascal MARTIN. Ese es el primer paso para depurar eso.

+1

Supongo que PHP entra en "secuencia de apagado" en todos estos casos. Consulte http://stackoverflow.com/questions/151660/php-destruct-method/8293937#8293937 para obtener más información. –

+0

Lo siento, sé que esto es viejo, pero ¿qué ocurre si el proceso se cancela? – dgig

+5

@dgig Si el proceso se cancela, el proceso muere. No se pregunta si le gusta morir, no se le da tiempo para hacer nada antes de morir, simplemente muere instantáneamente. Entonces no, '__destruct()' tampoco se ejecuta. – Shi

9

Como the PHP documentation dice:

El destructor será llamado incluso si la ejecución del script se dejó de usar exit(). Llamar al exit() en un destructor evitará que se ejecuten las rutinas restantes de apagado.

10

El método __destruct tampoco se llama si el script se ejecuta en CLI y recibe un SIGTERM (Ctrl +C)

1

Conozco I'am un poco tarde a la fiesta, pero para personas que también están buscando para obtener __destruct a ser ejecutado cuando CTRL +C y/o errores mortales se producen, puede probar esto (a continuación es un caso de prueba):

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 

Nota: llamando salida o lanzar excepciones en destructorsu funciones de apagado hará que la secuencia de comandos para terminar inmediatamente.

Cuestiones relacionadas