What determines when a class object is destroyed in PHP?
In PHP all values are saved in so called zval
s. Those zval
s contain the actual data, type information and - this is important for your question - a reference count. Have a look at the following snippet:
$a = new B; // $a points to zval(new B) with refcount=1$b = $a; // $a, $b point to zval(new B) with refcount=2 (+1)$c = $b; // $a, $b, $c point to zval(new B) with refcount=3 (+1)unset($a); // $b, $c point to zval(new B) with refcount=2 (-1)
As soon as the refcount
reaches 0
the zval
is freed and the object destructor is called.
Here are some examples of the refcount
reaching 0
:
unset
ing a variable:$a = new B; // refcount=1unset($a); // refcount=0 => __destruct!
But:
$a = new B; // refcount=1$b = $a; // refcount=2unset($a); // refcount=1 => no destruct as refcount > 0, even though unset() was called!
leaving function (or method) scope
function a() { $a = new B; // refcount=1} // refcount=0 => __destruct! (as $a does not exist anymore)
script execution end
$a = new B; // refcount=1die(); // refcount=0 => __destruct! (on script execution end all vars are freed)// doesn't need to be die(), can be just normal execution end
These obviously are not all conditions leading to a reduction of refcount
, but the ones you will most commonly meet.
Also I should mention that since PHP 5.3 circular references will be detected, too. So if object $a
references object $b
and $b
references $a
and there aren't any further references to $a
or $b
the refcount
s of both will be 1
, but they still will be freed (and __destruct
ed). In this case though the order of destruction is undefined behavior.
PHP 5 introduces a destructor concept similar to that of other object-oriented languages, such as C++. 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. - PHP Manual
If you want to see the process in action, you can run this code here.
<?phpclass A{ public function __construct() { var_dump('Creating: '. get_class($this)); } public function __destruct() { var_dump('Removing: '. get_class($this)); }}class B extends A {}$A = new A();/* * When this block is called later on */function create_b(){ $B = new B();} // At this point the function scope ends, and since $B is not referenced anymore it's removed.var_dump('B is next');create_b(); // Run above block, create, then destroy bevar_dump('B is now gone');// At this point the PHP file parser ends, $A is destroyed since it's not used anymore
The information is in the manual, albeit somewhat cryptic:
PHP 5 introduces a destructor concept similar to that of other object-oriented languages, such as C++. 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.
Meaning: The destructor will be called when the object gets destroyed (= e.g. unset()
), or when the script shuts down.
Additional useful info:
Like constructors, parent destructors will not be called implicitly by the engine. In order to run a parent destructor, one would have to explicitly call parent::__destruct() in the destructor body.
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.