Php Destruct называется дважды - PullRequest
3 голосов
/ 05 марта 2011

Код ниже иллюстрирует, что destruct () вызывается дважды. Я хотел бы знать, почему?

class A {
    function hi(){ echo 'hi'; }
    function __destruct(){
        echo 'destroy';
    }
}
class B{
    public $this_ = '';
    function __construct(){
        $this->this_ = new A;
    }
    function __call($method, $params) {
          return call_user_func_array(array($this->this_, $method), $params);
    }
}

$b = new B;
$b->__destruct();

выход:

destroydestroy

EDIT

И zneak, и TomcatExodus верны. Если я просто:

[..code..]
$b = new B;
$b->__destruct();
print 'end of script';

Вывод покажет:

destroyend of scriptdestroy

Ответы [ 4 ]

13 голосов
/ 05 марта 2011

Вызов уничтожить не разрушает объект.Вы вызываете его с __destruct() в первый раз, затем, когда скрипт PHP завершается, он вызывает его снова при очистке.

Если вы хотите уничтожить объект до завершения скрипта, unset() it.Вы должны увидеть только один сделанный вызов destruct.


В частности, ваш класс B создает автономный экземпляр класса A.Поскольку B также направляет вызовы методов через __call() к объекту A, поэтому вызов __destruct() на B вызывает __destruct() на A;B не определен деструктор и передает вызов.

10 голосов
/ 05 марта 2011

Поскольку B не имеет метода __destruct, вместо этого вызывается метод __call (это можно проверить, добавив что-то вроде echo "calling $method" в ваш метод __call), а затем он перенаправляется на ваш A объект.

Однако, вызов __destruct не уничтожает объект: он просто вызывает код очистки, который должен быть связан с его уничтожением. Поэтому, как только вы доберетесь до конца вашего скрипта, когда объект A будет фактически уничтожен, его метод __destruct будет вызван снова.

Если вы хотите удалить объект B, используйте unset($b).

2 голосов
/ 14 июня 2013

Вызов destructor вручную - одна из худших идей , особенно при работе с чужим кодом.У объекта есть логика, которая начинается с construct, проходит methods и заканчивается destruct.На destruct объект может потребовать некоторой очистки, а variables может быть признан недействительным. Когда destruct вызывается изнутри, в результате успешного unset($Object) объект больше не доступен.Когда вы делаете это вручную, объект все еще находится в пределах досягаемости, но не имеет поддержки внутренних переменных, если он сам выполняет некоторую очистку.

Теперь подумайте, как это было бы, если бы вы вызвали метод вобъект, который опирается на данные, которые вы сделали недействительными преждевременно после вызова destruct вручную.Это ломает всю логику! Так всегда unset() и пусть PHP делает свое дело.

Ручная деструктура (размещение удаления:)) потрясающе в C ++ если вы знаете, что делаете, особенно в сочетании с новым размещением .Но вы должны защищать себя на протяжении всей реализации и убедиться, что у вас действительно есть данные при вызове метода.И вы должны быть осторожны при уничтожении, если вы управляете памятью вручную, а не удаляете указатели ДВАЖДЫ и вылетаете в процессе.

Управление памятью так здорово в C ++!Я ненавижу GC (сборщики мусора) :)

--- RANT OVER ---

0 голосов
/ 06 марта 2011

Вы вызываете деструктор вручную; но это не значит, что вы удаляете объект. Вы просто вызываете метод, и этот метод просто , как и любой другой.

Вызов $b->__destruct() вызывает деструктор $b->this_, потому что $b не имеет явного метода деструктора.

Когда сценарий завершается, Zend Engine вызывает все созданные объекты их деструкторы, а затем выполняет обычную очистку, которая включает вызов деструкторов содержащихся объектов, т. Е. После уничтожения $b, $b->this_ должен быть очищен и, для этого Engine автоматически вызывает конструктор.

Обратите внимание, что второй вызов не из-за уничтожения $b, а из-за уничтожения экземпляра A.

Нет НИКАКОГО препятствия в уничтожении объекта вручную, и он освобождает свои ресурсы (если объект не используется совместно, и тогда GC не уничтожит его, если на него больше нет ссылок; в PHP нет слабые ссылки ).

Пример работы GC: http://codepad.org/7JDBoOKY

Объекты разрушаются до завершения кода. Если бы этого не было, порядок вывода был бы инвертирован.

...