Что определяет, когда объект класса уничтожается в PHP? - PullRequest
15 голосов
/ 15 декабря 2011

Допустим, у нас есть класс CFoo.В следующем примере, когда вызывается CFoo::__destruct()?

function MyPHPFunc()
{
  $foo = new CFoo();

  . . .

  // When/where/how does $foo get destroyed/deleted?
}

В этом примере будет ли вызываться деструктор, когда скрипт выходит из области действия MyPHPFunc, поскольку $foo больше не будет доступен?

Ответы [ 5 ]

36 голосов
/ 19 декабря 2011

В PHP все значения сохраняются в так называемых zval с.Эти zval содержат фактические данные, информацию о типе и - это важно для вашего вопроса - счетчик ссылок.Взгляните на следующий фрагмент:

$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)

Как только refcount достигает 0, zval освобождается и вызывается деструктор объекта.

Вот некоторыепримеры refcount достижения 0:

  • unset использования переменной:

    $a = new B; // refcount=1
    unset($a);  // refcount=0 => __destruct!
    

    Но:

    $a = new B; // refcount=1
    $b = $a;    // refcount=2
    unset($a);  // refcount=1 => no destruct as refcount > 0, even though unset() was called!
    
  • область выхода из функции (или метода)

    function a() {
        $a = new B; // refcount=1
    }               // refcount=0 => __destruct! (as $a does not exist anymore)
    
  • конец выполнения скрипта

    $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
    

Это, очевидно, невсе условия, приводящие к сокращению refcount, но те, которые вы будете чаще всего встречать.

Также я должен упомянуть, что, поскольку в PHP 5.3 также будут обнаруживаться циклические ссылки.Поэтому, если объект $a ссылается на объект $b и $b, ссылается на $a, и нет никаких дальнейших ссылок на $a или $b, то refcount s обоих будут 1, но онивсе еще будет освобожден (и __destruct ред).В этом случае порядок уничтожения не определен.

4 голосов
/ 19 декабря 2011

PHP 5 вводит концепцию деструктора, аналогичную концепции других объектно-ориентированных языков, таких как C ++.Метод деструктора будет вызываться, как только не будет никаких других ссылок на конкретный объект или в каком-либо порядке во время последовательности выключения.- PHP Manual

Если вы хотите увидеть процесс в действии, вы можете запустить этот код здесь .

<?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
2 голосов
/ 15 декабря 2011

Информация содержится в руководстве , хотя и несколько загадочно:

PHP 5 представляет концепцию деструктора, аналогичную концепции других объектно-ориентированных языков, таких как C ++. Метод деструктора будет вызываться, как только не будет никаких других ссылок на конкретный объект или в каком-либо порядке во время последовательности выключения.

Значение: деструктор будет вызван, когда объект будет уничтожен (= например, unset()), или когда скрипт выключится.

Дополнительная полезная информация:

Как и конструкторы, родительские деструкторы не будут вызываться механизмом неявно. Чтобы запустить родительский деструктор, необходимо явно вызвать parent :: __ destruct () в теле деструктора.

Деструктор будет вызван, даже если выполнение скрипта остановлено с помощью exit (). Вызов exit () в деструкторе предотвратит выполнение оставшихся подпрограмм выключения.

1 голос
/ 23 декабря 2011

лучший способ узнать это проверить.

однако простой ответ заключается в том, что __destruct вызывается во время очистки мусора. грубо говоря, это никому не помогает, так как очистка мусора - это непрерывный процесс, который очищает локальные переменные, когда нет области, которая может их вызвать.

однако здесь приведен пример кода и результат, который полностью объясняет, что происходит при внутреннем выходе из сценария.

<?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);

вывод этого странного набора классов функций и переменных:

I am number 2
I am number 1
I am number 3
I am not a number
I am number 4

это показывает нам, что конец функции вызывает __destruct, как и unset, и что по крайней мере на практике этот конец очистки скрипта выполняется в обратном порядке.

0 голосов
/ 26 декабря 2011

если создать экземпляр класса и использовать объект. После завершения всех ваших задач, если вы вызываете деструктор и снова используете тот же объект в следующей строке для выполнения какой-то другой задачи, которую вы больше не сможете использовать. Это означает, что ваш деструктор успешно вызван

...