Let's say that we have class CFoo
. In the following example when is CFoo::__destruct()
called?
function MyPHPFunc()
{
$foo = new CFoo();
. . .
// When/where/how does $foo get destroyed/deleted?
}
In this example would the destructor be called when the script exits the scope of MyPHPFunc
because $foo
would no longer be accessible?
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=1
unset($a); // refcount=0 => __destruct!
But:
$a = new B; // refcount=1
$b = $a; // refcount=2
unset($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=1
die(); // 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.
<?php
class 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 be
var_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.
the best way to know is to test.
however the simple answer is that __destruct is called during garbage cleanup. coarse that does not help anyone as garbage cleanup is an ongoing process that cleans up local variables when there is no scope that can call them.
however here is some sample code, and the result which fully explains what happens when exiting scope internally to the script.
<?php
class testingdestructor {
public function __construct($num) {
$this->num = $num;
}
public function __destruct() {
echo "I am number {$this->num}\n";
}
}
class testing2{
public function __construct($num) {
$this->classtest = new testingdestructor($num);
}
public function __destruct() {
echo "I am not a number\n";
}
}
$iam1 = new testingdestructor(1);
$iam4 = new testing2(4);
function testfunction() {
$iam2 = new testingdestructor(2);
}
testfunction();
$iam3 = new testingdestructor(3);
unset($iam1);
the output of this strange set of classes function and vars is this
I am number 2
I am number 1
I am number 3
I am not a number
I am number 4
this shows us that the end of the function calls the __destruct, as does unset, and that at least in practice that end of script cleanup is done in reverse order created.
if create instance of a class and use the object.after finishing all your tasks if u call the destructor and again use the same object in the next line to perform some other task u will be no longer able to use. That means ur destructor is called successfully