terminar method constructore codigo php image-processing memory-leaks destructor

method - PHP: destructor vs register_shutdown_function



php method constructor (4)

Tengo una clase PHP que crea una imagen PNG sobre la marcha y la envía al navegador. El manual de PHP dice que necesito asegurarme de que la función imagedestroy sea ​​llamada al final para liberar la memoria. Ahora, si no estuviera usando una clase, tendría un código como este:

function shutdown_func() { global $img; if ($img) imagedestroy($img); } register_shutdown_function("shutdown_func");

Sin embargo, creo que el lugar apropiado para mi clase sería hacer una llamada a imagedestroy en el destructor de la clase.

¿Fallé en descubrir si los destructores reciben el mismo nombre que las funciones de apagado? Por ejemplo, si la ejecución se detiene cuando el usuario presiona el botón DETENER en el navegador.

Nota: sea lo que sea que escriba en su respuesta, señale algún artículo o página de manual (URL) que lo admita.


Acabo de probar con Apache, PHP se utiliza como módulo de Apache. Creé un ciclo sin fin como este:

<?php class X { function __destruct() { $fp = fopen("/var/www/htdocs/dtor.txt", "w+"); fputs($fp, "Destroyed/n"); fclose($fp); } }; $obj = new X(); while (true) { // do nothing } ?>

Esto es lo que descubrí:

  • presionar el botón PARAR en Firefox no detiene esta secuencia de comandos
  • Si apago Apache, destructor no se llama
  • Se detiene cuando llega a PHP max_execution_time y el destinatario no se llama

Sin embargo, haciendo esto:

<?php function shutdown_func() { $fp = fopen("/var/www/htdocs/dtor.txt", "w+"); fputs($fp, "Destroyed2/n"); fclose($fp); } register_shutdown_function("shutdown_func"); while (true) { // do nothing } ?>

shutdown_func se llama. Entonces esto significa que el destuctor de clase no es tan bueno como las funciones de apagado.


Creo que una gran cosa que te has perdido es que toda la memoria que PHP ha asignado durante la ejecución del script se libera una vez que termina el script. Incluso si el usuario presiona el botón de detención, PHP procesa el script hasta que finaliza, lo devuelve al daemon HTTP para que se lo sirva al visitante (o no, dependiendo de qué tan inteligente sea el daemon).

Por lo tanto, liberar memoria explícitamente al final de la ejecución del script es un poco redundante. Algunos podrían argumentar que sería bueno hacerlo, pero sigue siendo redundante.

Pero, en el tema de los destructores de clase, se llaman siempre que el objeto se destruye, ya sea explícitamente por unset() o en la finalización / finalización del script.

La recomendación del desarrollador de liberar explícitamente la memoria utilizada en la manipulación de imágenes es seguro solo para asegurarse de no tener una pérdida de memoria, ya que los mapas de bits pueden estar forzando el lado de la memoria (alto * ancho * profundidad de bits * 3 (+ 1 si tienes un canal alfa))

Para satisfacer sus necesidades de Wikipedian:


Basado en el principio de que debes terminar lo que comienzas , diría que el destructor es el lugar correcto para la llamada gratuita.

Se llamará al destructor cuando se elimine el objeto, mientras que una función de apagado no se ejecutará hasta que finalice la ejecución del script. Como señaló Wolfie, esto no sucederá necesariamente si detiene el servidor o el script, pero en ese momento, la memoria asignada por PHP se liberará de todos modos.

También anotado por Wolfie, PHP liberará los recursos del script cuando se cierre el script, por lo que si solo está instanciando uno de estos objetos, entonces probablemente no notaría una gran diferencia. Sin embargo, si más tarde terminas instanciando estas cosas, o lo haces en un bucle, entonces probablemente no quieras tener que preocuparte por un aumento repentino en el uso de la memoria, por lo que en aras de la cordura futura, regreso a mi recomendación original; ponlo en el destructor.


Hace poco tuve problemas con esto ya que estaba tratando de manejar la destrucción específicamente para el caso en que el servidor experimenta un tiempo de espera y quería incluir datos de clase en el registro de errores. Recibiría un error al hacer referencia a & $ this (aunque lo he visto en algunos ejemplos, posiblemente un problema de versión o un efecto secundario de Symfony), y la solución que obtuve fue bastante clara:

class MyClass { protected $myVar; /** * constructor, registers shutdown handling */ public function __construct() { $this->myVar = array(); // workaround: set $self because $this fails $self = $this; // register for error logging in case of timeout $shutdown = function () use (&$self) { $self->shutdown(); }; register_shutdown_function($shutdown); } /** * handle shutdown events */ public function shutdown() { $error = error_get_last(); // if shutdown in error if ($error[''type''] === E_ERROR) { // write contents to error log error_log(''MyClass->myVar on shutdown'' . json_encode($this->myVar), 0); } } ...

¡Espero que esto ayude a alguien!