Поведение деструктора 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 */
    }
}