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

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

 function MyPHPFunc() { $foo = new CFoo(); . . . // When/where/how does $foo get destroyed/deleted? } 

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

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

 $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 

Очевидно, что это не все условия, приводящие к сокращению количества, но наиболее часто встречающиеся.

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

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

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

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

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

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

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

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

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

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

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

однако простой ответ заключается в том, что __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); 

вывод этого странного набора функций классов и vars – это

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

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

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