Предположим, что у нас есть класс 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, вы больше не сможете использовать. Это означает, что ур-деструктор называется успешно