How to Trust PHP _Destruct() Method to Be Called

Can I trust PHP __destruct() method to be called?

The destructor will be called when the all references are freed, or when the script terminates. I assume this means when the script terminates properly. I would say that critical exceptions would not guarantee the destructor to be called.

The PHP documentation is a little bit thin, but it does say that Exceptions in the destructor will cause issues.

How reliable is __destruct?

Let's have a class:

class A {
public function __construct(){
echo "Construct\n";
}

public function __destruct(){
echo "Destruct\n";
}
}

And test code:

$test = new A();
die( "Dead\n"); // Will output Construct; dead; Destruct

$test = new A();
throw new Exception("Blah\n"); // Construct, Fatal error (no destruct)

$test = new A();
require_once( 'invalid_file.php'); // Construct, Fatal error (no destruct)

So basically: there are situations (fatal errors) when destructor won't be called.

Ah and this question has the same answer as this one: When will __destruct not be called in PHP? (+/-)

Is the __destruct method necessary for PHP?

A destructor has nothing directly to do with releasing memory - instead it is a "hook" to allow custom code to be run when the object is eligible for reclamation. That is, it's the opposite of the constructor - the constructor does not allocate the memory (as that is done by the GC prior to the constructor being invoked) and thus the destructor does not release the memory (as that will be done by the GC afterwards).

While the GC can manage native resources (e.g. other objects and object graphs) just fine, external resources such as file handles must still be "manually disposed". For instance, imagine a MyFile class, where the destructor would ensure the file, if open, would be closed - while it is arguably "better" to make it a requirement to invoke a Close/Dispose operation upon the object, the destructor can be used as a fall-back mechanism in this case.

I would argue against the general use of destructors in languages with a GC. There are a number of subtle issues they can introduce such as apparent non-determinism and the ability to accidentally keep objects alive - even in languages like PHP that uses reference-counting. (The Java/JVM and .NET models use finalizers which are even more finicky.)

Happy coding.

Are there any instances when the destructor in PHP is NOT called?

  • According to the manual, destructors are executed even if the script gets terminated using die() or exit():

    The destructor will be called even if script execution is stopped using exit(). Calling exit() in a destructor will prevent the remaining shutdown routines from executing.

  • According to this SO question, the destructor does not get executed when PHP's execution time limit is reached (Confirmed on Apache 2, PHP 5.2 on Windows 7).

  • The destructor also does not get executed when the script terminates because the memory limit was reached. (Just tested)

  • The destructor does get executed on fatal errors (Just tested) Update: The OP can't confirm this - there seem to be fatal errors where things are different

  • It does not get executed on parse errors (because the whole script won't be interpreted)

  • The destructor will certainly not be executed if the server process crashes or some other exception out of PHP's control occurs.

All in all, it looks pretty reliable.

The downside of doing things other than cleanup in the destructor, though, is that your options there are somewhat limited. You can't throw exceptions any more (except if you catch them again inside the destructor), you can't output any error messages, you can't really rely on the presence of other objects (like the database interface) any more ..... I don't have deep experience in working with destructors but I'm not sure whether what you're planning to do is a feasible idea.

Does __destruct run by itslef or do I need to use unset() or register_shutdown_function() in order for it to work

No, the unset() function is not the only way to call __destruct(). According to the documentation, “the destructor method will be called as soon as there are no other references to a particular object, or in any order during the shutdown sequence”.

To illustrate this, consider the following methods when __destruct() will be called automatically:

1) It is called instantly when the class instance is not assigned to any variable:

<?php
new TheClass(); #-> this line calls __destruct()

/* More PHP Code */
?>

2) It is called when script execution is stopped:

<?php
$obj = new TheClass();
exit; #-> this line calls __destruct()

/* More PHP Code */
?>

3) It is called when unset() destroys the reference of the class:

<?php
$obj = new TheClass();
unset($obj); #-> this line calls __destruct()

/* More PHP Code */
?>

4) It is called when the value of variable is reassigned:

<?php
$obj = new TheClass();
$obj = 'any value'; #-> this line calls __destruct()

/* More PHP Code */
?>

5) It is called when the script completes its execution:

<?php
$obj = new TheClass();

/* More PHP Code */

#-> this line calls __destruct()
?>

6) It is called when exiting variable scope:

<?php
call_user_func(function() {
$obj = new TheClass();

/* More PHP Code */

return true; #-> this line calls __destruct()
});

/* More PHP Code */
?>

About __destruct() magic method and when it's invoked

The destructor method will be called as soon as there are no other references to a particular object, or in any order during the shutdown sequence.

The consumer's would be called first since it immediately has no reference. Then the store's when the script exits:

  • new Store() => Store construct
  • new Consumer() => Consumer construct => Store construct
  • (implicit delete of Consumer) => Consumer destruct => Store destruct
  • script exit => Store destruct

This is per object. Each object that is created/destroyed will have the construct/destruct methods called.



Related Topics



Leave a reply



Submit