поведение деструктора php - PullRequest
10 голосов
/ 06 мая 2010

я пытаюсь понять поведение конструктора php и деструктора.С конструктором все идет как положено, но у меня возникают проблемы с неявным срабатыванием деструктора.Я сделал все чтение на php.net и связанных сайтах, но я не могу найти ответ на этот вопрос.

Если у меня есть простой класс, что-то вроде:

class test{

     public function __construct(){
          print "contructing<br>";
     }

     public function __destruct(){
          print "destroying<br>";
     }
}

и явызовите его с чем-то вроде:

$t = new test;

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

Если я вызываю unset ($ t);когда сценарии заканчиваются, конечно, деструктор срабатывает, но есть ли способ заставить его срабатывать неявно?

спасибо за любые советы

Ответы [ 5 ]

16 голосов
/ 29 мая 2015

Это довольно легко проверить.

<?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

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

5 голосов
/ 06 мая 2010

Магическая функция __destruct() выполняется при удалении / уничтожении объекта (с использованием unset). Не вызывается во время отключения скрипта. Когда скрипт PHP завершает выполнение, он очищает память, но не «удаляет» объекты как таковые, поэтому методы __destruct() не вызываются.

Возможно, вы думаете о register_shutdown_function(), который запускается по завершении выполнения вашего PHP-скрипта.

function shutdown()
{
    // code here
    echo 'this will be called last';
}

register_shutdown_function('shutdown');
3 голосов
/ 26 ноября 2010

Насколько я понимаю, деструкторы автоматически вызываются для всех оставшихся объектов, когда скрипт заканчивается.

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

Используете ли вы exit() в любом из ваших деструкторов? Есть ли в вашем скрипте даже несколько объектов?

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

0 голосов
/ 27 мая 2019

Метод __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 */
    }
}
0 голосов
/ 12 января 2019

Метод __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 об источниках и подробных объяснениях методов магического разрушения с примерами.

...