Question

J'ai une classe PHP qui crée une image PNG à la volée et l'envoie au navigateur. Le manuel PHP dit que je dois m'assurer que la fonction imagedestroy est appelée à la fin pour libérer la mémoire. Maintenant, si je n'utilisais pas de classe, j'aurais un code comme celui-ci:

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

Cependant, je pense que l'endroit approprié pour ma classe serait de passer un appel à imagedestroy dans le destructeur de la classe.

Je n’ai pas réussi à savoir si les destructeurs sont appelés de la même manière que les fonctions d’arrêt? Par exemple, si l'exécution s'arrête lorsque l'utilisateur appuie sur le bouton STOP du navigateur.

Remarque: quelle que soit votre réponse, veuillez indiquer un article ou une page de manuel (URL) qui la prend en charge.

Était-ce utile?

La solution

Je viens de tester avec Apache, PHP étant utilisé comme module Apache. J'ai créé une boucle sans fin comme celle-ci:

<?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
}
?>

Voici ce que j'ai découvert:

  • appuyer sur le bouton STOP dans Firefox n'arrête pas ce script
  • Si je ferme Apache, le destructeur ne s'appelle pas
  • Il s'arrête lorsqu'il atteint PHP max_execution_time et que le destucteur ne s'appelle pas

Cependant, cela:

<?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 est appelé. Cela signifie donc que le destructeur de classe n’est pas aussi bon que les fonctions d’arrêt.

Autres conseils

Basé sur le principe selon lequel vous devriez terminer ce que vous commencez . , Je dirais que le destructeur est le bon endroit pour l’appel gratuit.

Le destructeur est appelé lorsque l'objet est éliminé, alors qu'une fonction d'arrêt ne sera appelée que l'exécution du script se termine. Comme l'a noté Wolfie, cela n'arrivera pas nécessairement si vous arrêtez de force le serveur ou le script, mais à ce moment-là, la mémoire allouée par PHP sera quand même libérée.

Également noté par Wolfie, PHP libérera des ressources de script à la fermeture du script. Par conséquent, si vous instanciez l’un de ces objets, vous ne remarquerez probablement pas une différence énorme. Cependant, si vous finissez par instancier ces choses plus tard ou en boucle, vous ne voudrez probablement pas avoir à vous soucier d'un pic soudain d'utilisation de la mémoire, alors pour des raisons de santé future, je reviens à ma recommandation originale; mettez-le dans le destructeur.

J'ai récemment eu des problèmes avec cela car j'essayais de gérer la destruction spécifiquement dans le cas où le serveur subissait un délai d'expiration et je voulais inclure les données de classe dans le journal des erreurs. Je recevrais une erreur lors de la référence à this (bien que je l’ai vu faire dans quelques exemples, éventuellement un problème de version ou un effet secondaire de symfony), et la solution que j’ai suggérée était assez propre:

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);
        }
    }

    ...

J'espère que cela aide quelqu'un!

Je pense que l’un des gros problèmes que vous avez oubliés est que toute la mémoire allouée par PHP lors de l’exécution du script est libérée une fois le script terminé. Même si l'utilisateur appuie sur le bouton stop, PHP traite le script jusqu'à ce qu'il soit terminé, le restitue au démon HTTP pour qu'il soit servi au visiteur (ou non, selon son habileté).

Donc, libérer explicitement de la mémoire à la fin de l'exécution du script est un peu redondant. Certains pourraient dire que ce serait une bonne chose à faire, mais cela reste redondant.

Mais, au sujet des destructeurs de classe, ils sont appelés chaque fois que l'objet est détruit, soit explicitement par unset () , soit à la fin / la fin du script.

La recommandation du développeur de libérer explicitement la mémoire utilisée dans la manipulation d'images est juste pour s'assurer absolument de ne pas avoir de fuite mémoire, car les bitmaps peuvent mettre à rude épreuve le côté mémoire de la chose (hauteur * largeur * profondeur 3 (+ 1 si vous avez un canal alpha))

Pour satisfaire vos besoins en wikipedian:

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top