What determines when a class object is destroyed i

2020-02-09 08:07发布

问题:

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?

回答1:

In PHP all values are saved in so called zvals. Those zvals 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:

  • unseting 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 refcounts of both will be 1, but they still will be freed (and __destructed). In this case though the order of destruction is undefined behavior.



回答2:

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


回答3:

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.



回答4:

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.



回答5:

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