Поведение деструктора php
im пытается понять конструктор php и поведение деструктора. Все идет так, как ожидалось, с конструктором, но у меня возникают проблемы с тем, чтобы деструктор не срабатывал неявно. Ive сделал все чтение на php.net и связанных сайтах, но я не могу найти ответ на этот вопрос.
Если у меня есть простой класс, то вроде:
class test{
public function __construct(){
print "contructing<br>";
}
public function __destruct(){
print "destroying<br>";
}
}
и я называю это чем-то вроде:
$t = new test;
он печатает сообщение конструктора. Тем не менее, я ожидаю, что когда сценарии закончится и страница будет отображаться, что деструктор должен срабатывать. Конечно, это не так.
Если я вызываю unset ($ t); когда скрипты заканчиваются, разумеется, деструктор срабатывает, но есть ли способ заставить его работать неявно?
спасибо за любые советы
Ответы
Ответ 1
Это довольно легко проверить.
<?php
class DestructTestDummy {
protected $name;
function __construct($name) {
echo "Constructing $name\n";
$this->name = $name;
}
function __destruct() {
echo "Destructing $this->name\n";
//exit;
}
}
echo "Start script\n";
register_shutdown_function(function() {
echo "Shutdown function\n";
//exit
});
$a = new DestructTestDummy("Mr. Unset");
$b = new DestructTestDummy("Terminator 1");
$c = new DestructTestDummy("Terminator 2");
echo "Before unset\n";
unset($a);
echo "After unset\n";
echo "Before func\n";
call_user_func(function() {
$c = new DestructTestDummy("Mrs. Scopee");
});
echo "After func\n";
$b->__destruct();
exit("Exiting\n");
В PHP 5.5.12 это печатает:
Start script
Constructing Mr. Unset
Constructing Terminator 1
Constructing Terminator 2
Before unset
Destructing Mr. Unset
After unset
Before func
Constructing Mrs. Scopee
Destructing Mrs. Scopee
After func
Destructing Terminator 1
Exiting
Shutdown function
Destructing Terminator 2
Destructing Terminator 1
Итак, мы видим, что деструктор вызывается, когда мы явно удаляем объект, когда он выходит из области видимости, и когда заканчивается script.
Ответ 2
Магическая функция __destruct()
выполняется, когда объект удаляется/уничтожается (используя unset
). Он не вызывается во время выключения script. Когда PHP скрипт завершает выполнение, он очищает память, но не удаляет объекты как таковые, поэтому методы __destruct()
не вызываются.
Возможно, вы думаете о register_shutdown_function()
, который запускается, когда ваш PHP скрипт завершает выполнение.
function shutdown()
{
// code here
echo 'this will be called last';
}
register_shutdown_function('shutdown');
Ответ 3
Я понимаю, что деструкторы автоматически вызываются для любых оставшихся объектов, когда заканчивается script.
Если посмотреть справочную страницу по конструкторам и деструкторам, кажется, единственный способ обойти деструкторы полностью, если вы вызываете exit()
из деструктор объекта, который разрушен до объекта, о котором идет речь.
Используете ли вы exit()
в любом из ваших деструкторов? Существуют ли даже несколько объектов в script?
Если это не так уж сложно, возможно, вы можете опубликовать фактический код, а не образец кода, который у вас есть в вашем вопросе. Помимо опечатки в вашем конструкторе образцов, этот код должен вызывать как constuctor, так и деструктор для вашего объекта test
.
Ответ 4
Метод __destruct класса вызывается, когда все ссылки на объект не установлены.
Например
$dummy = (object) new Class();
Деструктор вызывается автоматически, если фиктивный объект имеет значение null или сценарий завершается.
unset($dummy); // or $dummy = null;
//exit(); //also possible
Однако для вызова метода деструктора есть три важных момента в памяти:
Во-первых, метод desctructor должен быть открытым, не защищенным или закрытым.
Во-вторых, воздержитесь от использования внутренних и циклических ссылок. Например:
class NewDemo
{
function __construct()
{
$this->foo = $this;
}
function __destruct()
{
// this method will never be called
// and cause memory leaks
// unset will not clear the internal reference
}
}
Следующее также не будет работать:
$a = new Class();
$b = new Class();
$a->pointer = $b;
$b->pointer = $a;
unset($a); // will not call destructor
unset($b); // will not call destructor
В-третьих, решение, будут ли вызваны деструкторы после отправки вывода. С помощью
gc_collect_cycles()
Можно определить, все ли деструкторы вызываются перед отправкой данных пользователю.
См. Http://php.net/manual/en/language.oop5.decon.php для источников и подробное объяснение методов магического разрушения с примерами.
Ответ 5
Метод __destruct()
бесполезен. Лучше сделать что-то вроде этого:
class MyClass {
function __construct() {
register_shutdown_function([
&$this,
'the_end_game'
]);
}
function the_end_game() {
/* Your last part of code, save logs or what you want */
}
}