What is the "right way" to use PHP destructors

Asked

Viewed 265 times

2

When searching for references of good practices in PHP for memory management I came across several intentions of how to use destructors.

I know the leading actor is Garbage Collector but this is not part of the scope of my question.

References:

But my readings brought me questions which I could not find answers being them...

Doubts:

  • the function __destruct(){} empty will remove any value associated with the class or it is necessary to specify these values in its scope?
  • after instantiating the class by reference and before script termination what is the difference between using NULL and unset() for example:

    <?php
        $refer = new MyClass();
        $refer->hello(); // output: Hello World!
    
        $refer = NULL; // ou unset($refer);
    
        // mais blocos de código aqui...
    
  • according to Manual PHP class inheritance requires the class "daughter" to clarify the call parent::__destruct() in the destructor... but and in the case of extended classes that instantiate another class in its scope? When assigning NULL or use unset() before ending the script will force both destructors or it is necessary to explain each one? Example:

    <?php
        /**
        class Core
        {
             public function __construct(){}
    
             public function session($start=true)
             {
                 if ( !$start  ) {
                      if ( isset($_SESSION) ) {
                           session_destroy();
                           return true;
                      }
                 }
                 session_start();
             }
    
             public function language()
             {
                 if ( isset($_SESSION) ) {
                      $_SESSION['language'] = 'pt-BR';
                 }
             }
    
             public function layoutEngine()
             {
                 return new HandlerUI(); // outra classe
             }
    
             function __destruct(){
                 #
             }
        }
    
        class HandlerUI
        {
             function __construct()
             {
                 return $this;
             }
    
             public function Header()
             {
                 return "<head><title>Hello World</title></head>";
             }
    
             public function NavBar()
             {
                 return "<nav>This is navbar</nav>";
             }
    
             public function Drawer()
             {
                 return "<div class='drawer-container'></div>";
             }
    
             public function Footer()
             {
                 return "<footer>I am Footer</footer?";
             }
    
             public function JavaScript()
             {
                 return "<script type='text/javascript'>console.log('hola que tal');</script>";
             }
    
             function __destruct(){
                 #
             }
        }
        */
    
        // caso de uso:
        $app = new Core()
    
        $app->session();
        $app->language();
    
        $layout = $app->layoutEngine();
    
        unset($app); // ou $app = NULL;
    ?>
    <!DOCTYPE html>
    <html lang="<?php echo $_SESSION['language'];?>">
    <?php
        $layout->Header();
    ?>
    <body id="body">
        <!-- CONTAINER -->
        <section class="default">
            <?php
                // navbar
                $layout->Navbar();
                // drawer
                $layout->Drawer();
            ?>
    
            <!-- CENTRAL BLOCK -->
            <section id="central-block"></section>
            <?php
                //
                $layout->Footer();
            ?>
        </section>
        <?php
            //
            $layout->JavaScript();
    
            unset($layout); // ou $layout = NULL;
    
            // mais blocos de código aqui...
        ?>
    </body>
    </html>
    
  • and to which the more I question myself: when using Opcache or other cache of bytecode (that keeps the compiled in memory) how is treated fução __destruct() in this case of cache use?

I know that there is no "right way" since this depends on the use case, the needs of the code and the approach to structure it but I seek a qualified understanding of it.

Thank you in advance.

1 answer

2


The method __destruct serves to perform one last action before the object ceases to exist.

One use that can be made with it if you build a framework is to put it into a generic Controller by calling a view of the same name as the Controller at the end of the run. When other controllers extend this generic controller they will all have this feature to call the proper view automatically at the end of the run.

Code example using __Construct and __destruct :

<?php

class Teste
{
    private $nome;

    function __construct($nome)
    {
        echo 'O objeto foi construído.<br>';
        $this->nome = $nome;
    }

    function saudacao()
    {
        return 'Olá ' . $this->nome . '! <br>'; 
    }

    function __destruct()
    {
        echo 'O objeto não existirá mais após essa mensagem.';
    }   

}


$teste = new Teste('Lauro');

echo $teste->saudacao();


?>

Output generated when running the above script:

O objeto foi construído.
Olá Lauro!
O objeto não existirá mais após essa mensagem.

Remark: PHP wipes all variables from memory at the end of script execution. Then at the end of the script, when removing the object it automatically executes the destruct. But if the object was unset destroyed the destruct would be called in the same way, only before the execution of the script is complete.

No need to declare __Construct or __destruct if not using them.

  • Right bad, when using __destruct() should I wear unset() in its scope referring to values contained in the class in the case of using unset() on the occasion before the end of the instruction block? And if you wanted to "release" an instantiated index before the end of the instruction block in one instantiated class within another (not extended) would you call both destructors or just one? And when using Opcache a destructor would be really useful?

  • You should only use unset if you want the object to be destroyed before the end of the script execution. When destroying an object only one destructor is executed. It executes the parent destructor if it does not override the parent in the daughter class. That is, if he has a destroyer declared in the father and has not in the son, he executes that of the father. If he has a destroyer declared in the son, he executes that of the son. If you want to run both destructors, inside the son destructor call Parent:__destruct();

  • Yes the focus of the question is to destroy the object before the end of the script execution. As for my inheritance, my doubt is not about bad inheritance, but if: By "forcing" the destroyer of class "A" he would also force the destroyer of class "B" instantiated in class "A" (note that there is no inheritance among classes). What’s the difference between using NULL and unset() for this as well as if the use of Opcache does not counteract the use of destructors (since it saves in memory).

  • "netraliza" in my previous comment was a wrong word ... it would be something like: the use of Opcache does not make the work of destructors be in vain?

  • Opcache makes the scripts to be saved in memory pro php not need to load them, transform them into bytecode and execute each request. The bytecode is already in the memory. Although I have not yet used Opcache, the functioning of destructors should remain the same - My understanding is that the bytecode of the file in memory does not interfere with the variables during the execution of the script.

  • Reference to start using Opcache: http://stackoverflow.com/questions/17224798/how-to-use-php-opcache

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.