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






Деструктор будет вызван, когда все ссылки будут освобождены или когда сценарий завершится. Я предполагаю, что это означает, что сценарий завершается правильно. Я бы сказал, что критические исключения не гарантируют вызов деструктора.
Документация PHP немного тонок, но он говорит, что исключения в деструкторе вызовут проблемы.
Кроме того, вызов exit () внутри деструктора, который уже находится внутри последовательности exit (), может завершить процесс без вызова дополнительных деструкторов.
Извините, я не могу представить ваш пример. Не могли бы вы уточнить? @JasonCohen
Если вам нужно, чтобы деструктор вызывал даже в случае фатальной ошибки php, зарегистрируйте его как обработчик завершения работы в конструкторе: public function __construct() { register_shutdown_function(array($this, '__destruct')); }. Стоимость этого решения заключается в том, что ссылка на объект (и сам объект) существует до конца выполнения скрипта php. Тем не менее, есть случаи, когда они того стоят - например, удаление огромных файлов tmp в деструкторе.
Также стоит упомянуть, что в случае подкласса, у которого есть собственный деструктор, автоматически вызывается родительский деструктор нет.
Вы должны явно вызвать родитель :: __ destruct () из метода подкласса __destruct (), если родительский класс выполняет любую требуемую очистку.
Я считаю, что это верно только тогда, когда дочерний класс реализует свой собственный __destruct (), иначе будет вызван родительский __destruct ().
В настоящее время существует ошибка с циклическими ссылками, из-за которой неявно вызывается метод деструкции. http://bugs.php.net/bug.php?id=33595 Это должно быть исправлено в 5.3.
Он был закрыт в 5.3.
По моему опыту, деструкторы всегда будут вызываться в PHP 5.3, но имейте в виду, что если какой-то фрагмент кода вызывает exit () или если возникает фатальная ошибка, PHP вызовет деструкторы в «любом» порядке (я думаю, что фактический порядок - порядок в memory или порядок, в котором память была зарезервирована для объектов (на практике этот порядок почти всегда проблематичен). В документации PHP это называется «последовательностью выключения».
PHP-документация деструкторов говорит:
PHP 5 introduces a destructor concept similar to that of other object-oriented languages, such as C++. The destructor method will be called as soon as there are no other references to a particular object, or in any order during the shutdown sequence.
В результате, если у вас есть класс 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.
Обоснование PHP: «Я придерживаюсь текущей реализации, потому что считаю ее лучшим компромиссом. --Andi». Источник: mail-archive.com/[email protected]/msg06393.html
В основном есть две группы кодировщиков: (1) кодеры, использующие глобальные переменные в деструкторах и (2) кодеры, которые не используют глобальные переменные в деструкторах И правильно размечают зависимости, используя объектные ссылки на зависимые объекты. Поскольку PHP пытается нацелиться на нижнюю часть, он обслуживает (1) над (2). В группе (2) остался некорректно работающий код и нет официального способа решения проблемы.
См. Также: stackoverflow.com/questions/2385047/…
Используйте функцию выключения, если хотите точно: register_shutdown_function ()
Из документации: «Можно сделать несколько вызовов register_shutdown_function (), и каждый из них будет вызываться в том же порядке, в котором они были зарегистрированы. Если вы вызовете exit () в одной зарегистрированной функции выключения, обработка полностью прекратится, и никакое другое зарегистрированное выключение не будет функции будут вызываться ". Нет гарантии, что функция выключения ваш будет вызвана, если какая-то другая функция выключения будет запущена раньше вашей.
Могу сказать, что исключения во время завершения работы могут вызвать ошибки сегментации.