Могу ли я доверять вызову метода PHP __destruct ()? - PullRequest
39 голосов
/ 30 сентября 2008

В PHP5 гарантированно ли вызывается метод __destruct () для каждого экземпляра объекта? Могут ли исключения в программе предотвратить это?

Ответы [ 5 ]

41 голосов
/ 30 сентября 2008

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

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

36 голосов
/ 30 сентября 2008

Деструктор будет вызываться при освобождении всех ссылок или при завершении сценария. Я предполагаю, что это означает, когда скрипт завершается правильно. Я бы сказал, что критические исключения не гарантируют, что деструктор будет вызван.

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

12 голосов
/ 28 ноября 2011

По моему опыту, деструкторы всегда будут вызываться в PHP 5.3, но имейте в виду, что если какой-то фрагмент кода вызывает exit () или если возникает фатальная ошибка, PHP будет вызывать деструкторы в «любом» порядке (я думаю, что в действительности порядок это порядок в памяти или порядок, в котором память была зарезервирована для объектов. На практике этот порядок почти всегда проблематичен). В документации PHP это называется «последовательностью выключения».

PHP документация деструкторов говорит:

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

В результате, если у вас есть класс X, который содержит ссылку на Y, деструктор X может называться ПОСЛЕ того, как деструктор Y уже был вызван. Надеемся, что ссылка на Y была не так важна ... Официально это не ошибка, потому что она была задокументирована.

Однако, очень трудно обойти эту проблему, потому что официально PHP не предоставляет способа узнать, вызывается ли деструктор нормально (деструкторы вызываются в правильном порядке) или деструкторы вызываются в «любом» порядке, когда вы не можете использовать данные из ссылочных объектов. потому что те, возможно, уже были уничтожены. Можно обойти это отсутствие обнаружения, используя debug_backtrace () и исследуя стек. Отсутствие нормального стека, по-видимому, подразумевает «последовательность выключения» в PHP 5.3, но это тоже не определено. Если у вас есть циклические ссылки, деструкторы этих объектов вообще не будут вызываться в PHP 5.2 или ниже и будут вызываться в «любом» порядке во время «последовательности выключения» в PHP 5.3 или выше. Для циклических ссылок не существует логически «правильного» порядка, поэтому «любой» порядок подходит для них.

Есть некоторые исключения (в конце концов, это PHP):

  • если exit() вызывается в другом деструкторе, все остальные деструкторы не будут вызываться (http://php.net/manual/en/language.oop5.decon.php)
  • если ошибка FATAL возникнет где-либо (множество возможных причин, например, попытка выбросить исключение из любого другого деструктора, может быть одной из причин), то любые оставшиеся деструкторы не будут вызваны.

Конечно, если движок PHP сталкивается с ошибкой сегментации или возникает какая-либо другая внутренняя ошибка, тогда все ставки выключены.

Если вы хотите понять текущую реализацию "последовательности выключения", см. https://stackoverflow.com/a/14101767. Обратите внимание, что эта реализация может измениться в будущих версиях PHP.

10 голосов
/ 30 сентября 2008

В настоящее время существует ошибка с циклическими ссылками, которая останавливает неявный вызов метода destruct. http://bugs.php.net/bug.php?id=33595 Это должно быть исправлено в 5.3

8 голосов
/ 31 декабря 2011

Используйте функцию выключения, если вы хотите идти наверняка: register_shutdown_function ()

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...