Подтвердить что ты не робот

Как удалить объект PHP из своего класса?

Я знаю, что для некоторых, которые могут показаться глупыми, но я думал, если я hava метод delete() в классе, который удаляет все данные объекта (из базы данных и файловой системы), как я могу уничтожить/удалить объект изнутри класса.

Это вопрос PHP. Что-то вроде unset($this); Возможно ли и мудро? И каков правильный способ сделать это?

4b9b3361

Ответ 1

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

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

См. пример RaiseFile, класс, который представляет файл:

http://code.google.com/p/phpraise/source/browse/trunk/phpraise/core/io/file/RaiseFile.php

В классе RaiseFile, это будет разумно, что после того, как вы называете delete() метод и файл будет удален, объект RaiseFile также следует удалить.

Однако из-за проблемы, о которой вы упомянули, мне действительно нужно настаивать на том, что RaiseFile указывает на файл независимо от того, существует или нет файл. Существование файла можно отслеживать с помощью метода exists().

Скажем, у нас есть функция вырезания вставки, которая использует представление RaiseFile:

/**
 * Cut and paste a file from source to destination
 * @param string $file Pathname to source file
 * @param string $dest Pathname to destination file
 * @return RaiseFile The destination file
 */
function cutpaste($file, $dest){
    $f = new RaiseFile($file);
    $d = new RaiseFile($dest);
    $f->copy($d);
    $f->delete();
    return $d;
}

Обратите внимание, как $f удаляется и GC-ed после завершения функции, потому что больше нет ссылки на объект RaiseFile $f вне функции.

Ответ 2

Вы не можете отменить $this. Вернее: unset() on $this оказывает локальное влияние на переменную. unset() удаляет переменную из локальной области, что уменьшает количество ссылок для объекта. Если объект все еще упоминается где-то в другом месте, он останется в памяти и будет работать.

Как правило, значение свойства ID используется для определения того, хранится ли объект на заднем конце. Если идентификатор имеет правильное значение, этот объект сохраняется. Если идентификатор null, он еще не сохранен. При успешном хранении вы затем устанавливаете идентификатор. При удалении вы снова установите для свойства ID значение null.

Ответ 3

Сейчас я нахожусь в этой же лодке.

Я создаю решение CMS с нуля и имею много ссылок между объектами; пользователей, групп, категорий, форумов, тем, сообщений и т.д.

Я также использую загрузчик "Object:: getObject (id)" в каждом классе, который обеспечивает там только один экземпляр объекта на ID, но также означает, что еще проще для кода вывести ссылку на существующие объекты.

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

В идеале все ссылки должны быть удалены - ссылочный код может предоставить обратный вызов, который запускается при удалении объекта, который впоследствии может удалить/обновить ссылку. Но если ссылочный код становится неаккуратным, я бы предпочел, чтобы он ошибся с ошибкой "Нет объекта", чем фактически работает с объектом.

Не зная, как заставить разрушение внутри объекта, я сам вынужден:

  • Начните почти каждый нестатический метод с проверки, чтобы увидеть, был ли объект помечен как "удаленный", выбрасывая исключение, если оно есть. Это гарантирует, что любой ссылочный код не может навредить, но это неприятная вещь, чтобы посмотреть в коде.

  • Устанавливает каждую переменную объекта после удаления из базы данных, поэтому она не задерживается в памяти. Неважно, но, опять же: противно смотреть.

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

Ответ 4

Это зависит от того, как вы структурировали свой класс.

Если вы следуете шаблонам DTO/DAO, ваши данные будут отделены от вашей модели, и вы можете просто удалить DTO. Если вы этого не сделаете, просто отключите часть данных класса.

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

Ответ 5

Существует __ destruct() магический метод, который является деструктором для класса PHP.

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

Ответ 6

Другой подход заключается в том, чтобы сделать статический метод delete, который затем может получить объект и данные PDO, который определяет, что нужно удалить. Таким образом, вам не нужно инициализировать объект.

Ответ 7

Вот пример решения, которое было бы "разумно использовано", когда оно было бы реализовано в четко определенных соотношениях/шаблонах ссылок, как правило, в своих композитах я бросаю что-то подобное. Фактически использовать текущий код, как я делал в этом примере, в реальной жизни будет слишком много проблем, но это просто для иллюстрации метода "точка-точка".

Объект не может просто волшебным образом исчезнуть - его удалят только (собирают мусор), когда нет ничего, указывающего на него. Таким образом, "все" объект должен делать, это следить за всем, что относится к нему. Это довольно низкое трение, когда у вас все встроенное референсное управление - объекты создаются и передаются только фиксированными методами.

Давайте начнем с простого интерфейса, чтобы мы могли определить, безопасно ли передавать нашу ссылку на объект или нет.

interface removableChildInterface
{

    public function removeChild($obj);

}

Класс, который может смело содержать ссылку на наш объект.

class MyParent implements removableChildInterface
{

    public $children = array();

    public function removeChild($child)
    {
        $key = array_search($child, $this->children);
        unset($this->children[$key]);
    }

}

И, наконец, класс с возможностью самоуничтожения aka запускает процесс удаления всех его родителей.

class Suicidal
{

    private $parents = array(); // Store all the reference holders
    private $id; // For example only
    private $memory = ''; // For example only
    public static $counter = 0; // For example only

    public function __construct(&$parent)
    {
        // Store a parent on creation
        $this->getReference($parent);
        // For the example lets assing an id
        $this->id = 'id_' . ++self::$counter;
        // and generate some weight for the object.
        for ($i = 0; $i < 100000; $i++) {
            $this->memory .= md5(mt_rand() . $i . self::$counter);
        }
    }

    // A method to use for passing the object around after its creation.
    public function getReference(&$parent)
    {
        if (!in_array($parent, $this->parents)) {
            $this->parents[] = &$parent;
        }
        return $this;
    }

    // Calling this method will start the removal of references to this object.
    // And yes - I am not actually going to call this method from within this
    // object in the example but the end result is the same.
    public function selfDestruct()
    {
        foreach ($this->parents as &$parent) {
            if (is_array($parent)) {
                $key = array_search($this, $parent);
                unset($parent[$key]);
                echo 'removing ' . $this->id . ' from an array<br>';
            } elseif ($parent instanceof removableChildInterface) {
                $parent->removeChild($this);
                echo 'removing ' . $this->id . ' from an object<br>';
            }
            // else throw your favourite exception
        }
    }

    // A final shout out right before being garbage collected.
    public function __destruct()
    {
        echo 'destroying ' . $this->id . '<br>';
    }

}

И для примера использования, удерживая ссылку в array, в object, реализующей наши interface и $GLOBALS array.

// Define collectors
$array = array();
$parent = new MyParent();

// Store objects directly in array
$array['c1'] = new Suicidal($array);
$array['c2'] = new Suicidal($array);

// Make a global reference and store in object
$global_refrence = $array['c1']->getReference($GLOBALS);
$parent->children[] = $array['c1']->getReference($parent);

// Display some numbers and blow up an object.
echo 'memory usage with 2 items ' . memory_get_usage() . ' bytes<br>';
$array['c1']->selfDestruct();
echo 'memory usage with 1 item ' . memory_get_usage() . ' bytes<br>';

// Second object is GC-d the natural way after this line
echo '---- before eof ----' . '<br>';

Вывод:

memory usage with 2 items 6620672 bytes
removing id_1 from an array
removing id_1 from an array
removing id_1 from an object
destroying id_1
memory usage with 1 item 3419832 bytes
---- before eof ----
destroying id_2