PHP: destructor vs register_shutdown_function

У меня есть класс PHP, который создает изображение PNG на лету и отправляет его в браузер. В руководстве PHP говорится, что мне нужно убедиться, что функция imagedestroy вызывается в конце для освобождения памяти. Теперь, если бы я не использовал класс, у меня был бы такой код:

function shutdown_func() { global $img; if ($img) imagedestroy($img); } register_shutdown_function("shutdown_func"); 

Тем не менее, я считаю, что подходящим местом для моего класса было бы поместить вызов imagedestroy в класс-деструктор.

Мне не удалось выяснить, вызваны ли деструкторы так же, как это делают функции shutdown? Например, если выполнение останавливается, когда пользователь нажимает кнопку STOP в браузере.

Примечание: независимо от того, что вы пишете в своем ответе, укажите на странице статьи или руководства (URL), которая ее поддерживает.

Solutions Collecting From Web of "PHP: destructor vs register_shutdown_function"

Я просто протестировал с Apache, PHP использовался как модуль Apache. Я создал бесконечный цикл:

 <?php class X { function __destruct() { $fp = fopen("/var/www/htdocs/dtor.txt", "w+"); fputs($fp, "Destroyed\n"); fclose($fp); } }; $obj = new X(); while (true) { // do nothing } ?> 

Вот что я узнал:

  • нажатие кнопки STOP в Firefox не останавливает этот скрипт
  • Если я отключу Apache, деструктор не будет вызван
  • Он останавливается, когда он достигает PHP max_execution_time, а destuctor не вызван

Однако, делая это:

 <?php function shutdown_func() { $fp = fopen("/var/www/htdocs/dtor.txt", "w+"); fputs($fp, "Destroyed2\n"); fclose($fp); } register_shutdown_function("shutdown_func"); while (true) { // do nothing } ?> 

Вызывается shutdown_func. Таким образом, это означает, что класс destuctor не так хорош, как функции выключения.

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

Деструктор вызывается, когда объект удаляется, тогда как функция выключения не будет вызываться до завершения выполнения сценария. Как отметил Wolfie, это не обязательно произойдет, если вы принудительно остановите сервер или сценарий, но в то время память, выделенная PHP, будет в любом случае освобождена.

Также отметил Вольфье, PHP освободит ресурсы скрипта, когда скрипт закроется, поэтому, если вы создаете экземпляр только одного из этих объектов, то, вероятно, вы не заметите огромных различий. Однако, если вы позже закончите создание этих вещей или сделаете это в цикле, тогда вы, вероятно, не захотите беспокоиться о внезапном всплеске в использовании памяти, поэтому ради будущего здравого смысла я возвращаюсь к своим оригинальная рекомендация; поместите его в деструктор.

У меня недавно возникли проблемы с этим, поскольку я пытался справиться с уничтожением специально для случая, когда сервер испытывает таймаут, и я хотел включить данные класса в журнал ошибок. Я получал бы ошибку при ссылках & $ this (хотя я видел это в нескольких примерах, возможно, в версии или побочном эффекте symfony), и решение, которое я придумал, было довольно чистым:

 class MyClass { protected $myVar; /** * constructor, registers shutdown handling */ public function __construct() { $this->myVar = array(); // workaround: set $self because $this fails $self = $this; // register for error logging in case of timeout $shutdown = function () use (&$self) { $self->shutdown(); }; register_shutdown_function($shutdown); } /** * handle shutdown events */ public function shutdown() { $error = error_get_last(); // if shutdown in error if ($error['type'] === E_ERROR) { // write contents to error log error_log('MyClass->myVar on shutdown' . json_encode($this->myVar), 0); } } ... 

Надеюсь, это поможет кому-то!

Я думаю, что одна большая вещь, которую вы пропустили, состоит в том, что вся память, выделенная PHP во время выполнения скрипта, освобождается после завершения сценария. Даже если пользователь нажимает кнопку останова, PHP обрабатывает скрипт до его завершения, возвращает его демону HTTP, который будет обслуживаться посетителю (или нет, в зависимости от того, насколько умным является демон).

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

Но по теме деструкторов класса они вызывается всякий раз, когда объект уничтожается, либо явно, либо unset() либо при завершении / завершении скрипта.

Рекомендация разработчика, явно освобождающая память, используемую при манипуляциях с изображениями, обязательно должна быть абсолютно уверена, что не будет утечки памяти, поскольку растровые изображения могут быть напряженными на стороне памяти вещей (высота * ширина * глубина бит * 3 (+ 1, если у вас есть альфа-канал))

Чтобы удовлетворить ваши потребности в Википедии: