В приведенном ниже коде показано, что 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
РЕДАКТИРОВАТЬ
Правильно указаны как zneak, так и TomcatExodus. Если я просто:
[..code..] $b = new B; $b->__destruct(); print 'end of script';
На выходе будет показано:
destroyend of scriptdestroy
Вызов destruct не уничтожает объект. Вы вызываете его с помощью __destruct()
в первый раз, а затем, когда PHP-скрипт завершается, он снова вызывает его при очистке.
Если вы хотите уничтожить объект до завершения сценария, unset()
. Вы должны увидеть только один вызов разрушения.
В частности, ваш класс B
создает отдельный экземпляр класса A
Так как B
также маршрутизирует вызовы методов через __call()
в объект A
, поэтому __destruct()
на B
вызывает __destruct()
на A
; B
не имеет деструктора, определенного и передает вызов.
Поскольку B
не имеет метода __call
вместо него __destruct
метод __call
(вы можете проверить это, добавив что-то вроде echo "calling $method"
вашему методу __call
), а затем он будет перенаправлен на ваш объект A
Однако вызов __destruct
не уничтожает объект: он просто вызывает код очистки, который должен быть связан с его уничтожением. Поэтому, как только вы закончите свой сценарий, когда объект A
фактически уничтожен, его метод __destruct
вызывается снова.
Если вы хотите удалить свой объект B
, используйте unset($b)
.
Вызов destructor
вручную – одна из худших идей , особенно при работе с кодом других. Объект имеет логику, которая начинается с construct
, проходит через methods
и заканчивается при destruct
. При destruct
объект может потребовать некоторой очистки, а variables
могут быть аннулированы. Когда destruct
вызывается внутренне, в результате unset($Object)
объект больше не доступен. Когда вы делаете это вручную, объект все еще находится в пределах досягаемости, но не поддерживает внутреннюю переменную, если он выполняет некоторую очистку.
Теперь подумайте, как бы это было, если вы вызвали метод на объекте, который полагается на данные, которые вы ранее недействительны, после обращения к
destruct
вручную. Это нарушает всю логику! Поэтому всегдаunset()
и пусть PHP делает свое дело.
Ручное уничтожение (размещение delete :)) является удивительным на C ++, если вы знаете, что делаете, особенно в сочетании с размещением нового . Но вы должны охранять себя на протяжении всей реализации и убедиться, что на самом деле у вас есть данные при вызове метода. И вы должны охранять себя в разрушении, если вы управляете памятью вручную, а не удалять указатели TWICE и сбой в этом процессе.
Управление памятью настолько круто в C ++! Я ненавижу GC (сборщики мусора) 🙂
— RANT OVER —
Вы вызываете деструктор вручную; но это не означает, что вы удаляете объект. Вы просто вызываете метод, и этот метод аналогичен любому другому.
Вызов метода $b->__destruct()
вызывает $b->__destruct()
$b->this_
, потому что $b
не имеет явного метода деструктора.
Когда сценарий завершается, Zend Engine вызывает все экземпляры объектов, их деструкторы, а затем выполняет рутинную очистку, которая включает вызов деструкторов содержащихся объектов, т. $b->this_
После уничтожения $b
, $b->this_
должен быть очищен и, чтобы сделать что, Двигатель вызывает свой конструктор автоматически.
Обратите внимание, что второй вызов не связан с уничтожением $b
а из-за разрушения экземпляра A
Нет никакого препятствия в уничтожении объекта вручную, и он освобождает его ресурсы (если только объект не используется совместно, а затем GC не уничтожит его, если на нем больше нет ссылок, в PHP нет слабых ссылок ).
Пример работы GC: http://codepad.org/7JDBoOKY
Объекты разрушаются до завершения кода. Если бы это было не так, то порядок вывода был бы инвертирован.