ejemplos - ¿Cuándo__destruct no se llamará en PHP?
php constructor parameters (6)
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 anterior se encuentra en un entorno complejo , la __destruct
no se llamará cuando exit
, pero no puedo reproducirla fácilmente. ¿Alguna vez alguien se ha dado cuenta de esto?
EDITAR
Voy a publicar todo el contenido aquí, es el entorno de prueba de Symfony, lo que significa que puedes reproducirlo fácilmente si estás 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();
Como dice la documentación de PHP :
Se llamará al destructor incluso si la ejecución del script se detiene con
exit()
. Llamar aexit()
en un destructor evitará que se ejecuten las rutinas de cierre restantes.
El hecho de no tener un resultado en la pantalla no significa que no se invoque el destructor: el ouptut se puede capturar usando output_buffering (¿quizás lime lo haga, para poder trabajar en él?) , Y no se repite cuando termina el script, por ejemplo .
Para fines de prueba, puede intentar escribir en un archivo, en su método __destruct
, en lugar de hacer eco de algún texto.
(Solo asegúrese de que su aplicación / PHP tenga los privilegios necesarios para escribir en su archivo de destino)
(Ya me encontré con situaciones en las que no vería la salida realizada en un destructor, pero en realidad se llamó)
El método __destruct
tampoco se __destruct
si el script se ejecuta en CLI y recibe un SIGTERM ( Ctrl + C )
La __destruct
no se llamará:
- Si se llama a
exit
en otro destructor - Según la versión de PHP: si se llama a la
exit
en una función de apagado registrada conregister_shutdown_function
- Si hay un error fatal en algún lugar del código
- Si otro destructor arroja una excepción
- Si intenta manejar una excepción en un destructor (PHP> = 5.3.0)
Supongo que es todo lo que puedo pensar en este momento
& Qué dijo Pascal MARTIN. Ese es el primer paso para depurar eso.
No está familiarizado con la Doctrina, pero verifique un punto: verifique las posibles excepciones en __construct () / __ destruct () pueden producir errores fatales.
Sé que llego un poco tarde a la fiesta, pero para las personas que también __destruct
que __destruct
se ejecute cuando se producen errores CTRL + C y / o fatales, puede intentarlo (a continuación se muestra 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: si se llama a la salida o se lanzan excepciones en los destructores o en las funciones de apagado, la secuencia de comandos finalizará inmediatamente.