Comment supprimer un objet PHP de sa classe?

je sais que pour certains qui pourraient sembler stupides, mais je pensais que si j'avais une méthode delete () dans une classe qui supprime toutes les données de l'objet (à partir de la base de données et du système de fichiers), comment pourrais-je détruire/supprimer l'objet de l'intérieur de la classe.

C'est une question PHP. Quelque chose comme unset($this); est-ce possible et sage? Et quelle est la bonne façon de le faire?

10
demandé sur Yasen Zhelev 2011-03-03 15:00:56

7 réponses

Tout en développant un cadre, je suis tombé sur une telle question. unset($this) est totalement impossible, comme $this est juste un indicateur spécial qui vous permet d'accéder aux propriétés de l'objet et des méthodes.

Le seul moyen est de encapsuler l'utilisation d'objets dans des méthodes / fonctions de sorte que lorsque la méthode / fonction se termine, la référence à l'objet est perdue et le collecteur d'ordures libèrera automatiquement la mémoire pour d'autres chose.

Voir l'exemple RaiseFile, une classe qui représente un fichier:

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

dans la classe RaiseFile, il sera raisonnable que vous appeliez le delete() méthode et le fichier est supprimé, l'objet RaiseFile doit aussi être supprimé.

Cependant en raison du problème que vous avez mentionné, j'ai en fait insister pour que RaiseFile pointe vers un fichier que le fichier existe ou non. L'Existence du fichier peut être retracée par exists() méthode.

disons que nous avons une fonction cut-paste qui utilise la représentation du fichier 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;
}

Remarquez comment $f est supprimé et GC-ed après la fin de la fonction parce qu'il n'y a plus de références à RaiseFile objet $f en dehors de la fonction.

6
répondu mauris 2011-11-14 04:58:14

Vous ne pouvez pas annuler $this. Ou plus correctement: unset()$this n'a qu'un effet local sur la variable. unset() supprime la variable de la portée locale, ce qui réduit le nombre de références pour l'objet. Si l'objet est encore référencé ailleurs, il restera dans la mémoire et fonctionnera.

généralement, la valeur D'une propriété ID est utilisée pour déterminer si un objet est stocké à l'arrière. Si L'ID a une valeur correcte, Cet objet est stocké. Si l'IDENTIFIANT est null, il n'est pas stockées, encore. Sur le stockage réussi vous définissez alors L'ID en conséquence. Sur supprimer vous définissez la propriété ID null nouveau.

3
répondu tobyS 2011-03-03 12:18:51

je suis dans le même bateau.

je suis en train de construire une solution CMS à partir de la base et j'ai beaucoup de références entre les objets; Utilisateurs, Groupes, catégories, forums, Sujets, Messages, etc.

j'utilise aussi un chargeur" Object::getObject(id) " dans chaque classe qui assure qu'il n'y a qu'une seule instance d'un objet par ID, mais cela signifie aussi qu'il est encore plus facile pour le code de tirer une référence à des objets existants.

lorsque les données que l'objet représente sont supprimées de la source de données, je voudrais effacer l'objet de la mémoire et annuler toutes les références à elle pour s'assurer que d'autres code n'essaye pas d'utiliser un ensemble de données obsolète.

idéalement, toutes les références devraient être supprimées--le code de référence peut fournir un rappel qui est lancé à la suppression d'objet qui peut ensuite supprimer/mettre à jour la référence. Mais si le code de référencement devient négligent, je préfère qu'il se trompe avec une erreur "pas un objet" plutôt que de travailler avec l'objet.

Sans sachant comment forcer la destruction de l'intérieur de l'objet, lui-même, je suis forcé de:

  1. commencez presque toutes les méthodes non statiques avec une vérification pour voir si l'objet a été marqué "supprimé", en lançant une exception si elle l'est. Cela garantit que tout code de référence ne peut pas faire de mal, mais c'est une chose désagréable à regarder dans le code.

  2. désactivez toutes les variables objet après suppression de la base de données, de sorte qu'elles ne restent pas en mémoire. Pas une grosse affaire mais, encore une fois: désagréable à regarder.

ni L'un ni l'autre ne serait nécessaire si je pouvais simplement détruire l'objet de l'intérieur.

1
répondu Rikaelus 2012-07-11 07:24:49

Cela dépend de comment vous avez structuré votre classe.

si vous suivez les modèles DTO/DAO, vos données seront séparées de votre modèle et vous pouvez simplement supprimer le DTO. Si vous ne l'êtes pas, il suffit de désactiver la partie données de la classe devrait le faire.

mais en fait, je pense que C'est inutile puisque PHP nettoiera automatiquement à la fin de la requête. Sauf si vous travaillez sur un objet géant qui prend des quantités massives de mémoire, et c'est un long processus c'est pas vraiment la peine l'effort.

0
répondu JohnP 2011-03-03 12:05:50

il y a un __autodétruire() méthode magique qui est un destructeur pour une Classe PHP.

Peut-être que vous pouvez mettre votre code de suppression là et dès que toutes les références aux objets sont supprimés, ce destructeur sera appelé et les données supprimées.

0
répondu krtek 2011-03-03 12:06:40

une autre approche consiste à rendre la méthode delete statique, qui pourrait alors recevoir un objet et des données AOP, qui détermine ce qu'il faut supprimer. De cette façon, vous n'avez pas besoin d'initialiser l'objet.

0
répondu feeela 2011-03-29 13:57:48

voici un exemple de solution qui serait "raisonnablement utilisable" lorsqu'elle est mise en œuvre dans des modèles de relation/référence bien définis, habituellement je laisse tomber quelque chose comme ça dans mes composites. Utiliser réellement le code actuel comme je l'ai fait dans cet exemple dans une vraie vie serait passer par trop de problèmes, mais c'est juste pour illustrer le comment-à-point.

un objet ne peut pas simplement disparaître par magie - il ne sera supprimé (ordures collectées) qu'une fois qu'il n'y a rien pointant vers lui. Si "tout" qu'un objet doit faire est de garder une trace de tout ce qui s'y réfère. Il est assez faible friction quand vous avez toute la gestion de référence intégrée - les objets sont créés et transmis seulement par des méthodes fixes.

commençons par une interface simple pour que nous puissions dire s'il est sûr de passer notre référence à un objet ou non.

interface removableChildInterface
{

    public function removeChild($obj);

}

une classe qui peut contenir en toute sécurité une référence à notre objet.

class MyParent implements removableChildInterface
{

    public $children = array();

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

}

Et enfin une classe avec le la capacité d'autodestruction déclenche le processus d'être enlevé par tous ses parents.

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>';
    }

}

et pour l'exemple d'usage, maintenir la référence dans un array dans un object mise en oeuvre de notre interface et $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>';

Sortie:

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
0
répondu Jaak Kütt 2014-01-26 17:50:25