Когда (в какой момент) вызывается __destruct?

Есть ли какая-то уверенность при вызове __destruct при рассмотрении простых объектов без циклов ссылок? Я знаю из java, что не определено, когда и если вызывается функция finalize, это зависит от сборщика мусора.

Например, если у вас есть такая функция, как:

1   function test(){
2       $x = new SomeObject();
3       $y = new SomeObject();
4       $x = null;
5   }

Где SomeObject не имеет эталонных циклов.

Можете ли вы предположить, что $x->__destruct вызывается в строке 4, а $y->__destruct вызывается в строке 5?

Тестирование следующего скрипта, по-видимому, указывает на то, что это правда:

Кроме того, SplFileObject, кажется, работает с этим предикатом: невозможно закрыть файл, вместо этого вам просто нужно установить переменную в null. Если бы это не вызывало __destruct напрямую, было бы невозможно надежно открыть файл после того, как он был открыт с помощью SplFileObject.

Я обнаружил, что есть гарантия того, что __destruct будет вызвана в конце концов, но не когда.


person user23127    schedule 11.05.2014    source источник


Ответы (1)


Да, вы можете предположить это.

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

Если существуют циклические ссылки, вам нужно подождать, пока не появится циклический сборщик мусора, где не определено, в какой момент это произойдет.

Если вы сохранили объект где-то еще, вам нужно сначала удалить его оттуда до вызова деструктора.

Для получения дополнительной информации: Внутренние объекты не всегда уничтожают свои ресурсы при __destruct (как пользователь может вызвать это напрямую), а только тогда, когда объект действительно уничтожается. (техническая мера для предотвращения segfaults)

Также во время завершения работы первые переменные и массивы удаляются в обратном порядке, в котором они были определены, и там, где исчезает последняя ссылка на объект, объект уничтожается. Затем приходит круговой сборщик мусора, удаляет другие объекты и вызывает там __destruct.

Единственное, что здесь не определено, — это порядок, в котором циклический сборщик мусора удаляет объекты и вызывает их __destruct функцию.

person bwoebi    schedule 11.05.2014
comment
«когда вы больше не можете получить доступ к этому объекту извне». Не совсем верно, рассмотрим объект: gist.github.com/KAYLukas/5d91aa17c6173f426a7d. Деструктор будет вызываться только после запуска gc (круговой сборщик ссылок). В любом случае (самита прокомментировала документацию) в документации говорится: «Метод деструктора будет вызван, как только не будет других ссылок на конкретный объект, или в любом порядке во время последовательности завершения работы». Поэтому, если вы обновите свой ответ, я приму его. - person user23127; 11.05.2014
comment
@ user23127 на самом деле большая часть этого уже неявно указана в моем ответе. Но я обновил его информацией. Также во время выключения это не в любом порядке, а в известном порядке, но просто не задокументированном. - person bwoebi; 11.05.2014
comment
@user23127 небольшая ошибка, переменные на самом деле уничтожаются в обратном порядке lxr.php.net/xref/PHP_TRUNK/Zend/zend_execute_API.c#247 исправил это. - person bwoebi; 11.05.2014
comment
для моей цели я не рассматриваю, как это делается сейчас - это легко выяснить при тестировании - но если это задокументировано, и как таковое не изменится в последующих обновлениях. - person user23127; 12.05.2014
comment
@user23127 user23127 на самом деле, большинство вещей здесь не задокументированы и могут быть изменены. Но, насколько я могу судить сейчас (будучи участником php-src), на самом деле нет планов что-то менять. Так что вы должны быть в безопасности, по крайней мере, для следующих двух версий, я думаю. - person bwoebi; 12.05.2014