IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

[POO] Destruction d'objet et de ses références


Sujet :

Langage PHP

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 7
    Points : 5
    Points
    5
    Par défaut [POO] Destruction d'objet et de ses références
    Bonjour à tous,

    Mon problème est simple mais je ne trouve pas la solution. J'aimerai pouvoir supprimer un objet (et donc appeler sa fonction __destruct()) alors que plusieurs référence lui sont rattachées.

    J'utilise PHP 5.2.10

    Puisqu'un bon bout de code vaux mieux qu'un long discours… si si!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    class Object{
    	public static $collection;
    	protected $internal_uuid;
     
    	public static function factory($uuid = null){
    		if(isset(self::$collection[$uuid])){
    			return self::$collection[$uuid];
    		}else{
    			return new Object();
    		}
    	}
     
    	protected function __construct(){
    		$this->uuid();
    		/* Bon je vous copie pas tous le code mais en gros cette fonction affecte,
    		* vous l'aurai compris, un identifiant unique a $this->internal_uuid.
    		*/
     
    		self::$collection[$this->internal_uuid] = $this;
    	} 
     
    	public function __destruct(){
    		echo '__destruct';
    	}
    }
     
    	//Après la déclaration de la classe, ben… on s'en sert.
    $oObject = Object::factory();
    unset($oObject);
    echo '*** FIN DU SCRIPT ***';

    L'exécution de ce bout de code nous donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    *** FIN DU SCRIPT ***
    __destruct

    Ce qui est tout a fait normal car la référence à notre objet se trouve encore dans Object::collection après le unset et c'est donc a la fin de l'exécution du script que l'appel à __destruct se fait.

    Ce que j'aimerai donc obtenir c'est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    __destruct
    *** FIN DU SCRIPT ***
    Avec Object::collection[<identifiant unique de mon instance>] == NULL juste après l'appel de unset($oObject)




    Quelqu'un a-t-il une idée ? Je m'arrache les cheveux la dessus… j'ai essayé dans tous les sens avec référence, sans référence (bon même si elles sont implicite en PHP5)

  2. #2
    Membre averti Avatar de FredPsy
    Homme Profil pro
    Formateur en informatique
    Inscrit en
    Décembre 2006
    Messages
    285
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Formateur en informatique
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Décembre 2006
    Messages : 285
    Points : 342
    Points
    342
    Par défaut
    Eh comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    class Object{
        public static $collection;
        protected $internal_uuid;
     
        public static function factory($uuid = null){
            if(isset(self::$collection[$uuid])){
                return self::$collection[$uuid];
            }else{
                return new Object();
            }
        }
     
        protected function __construct(){
            $this->uuid();
            /* Bon je vous copie pas tous le code mais en gros cette fonction affecte,
            * vous l'aurai compris, un identifiant unique a $this->internal_uuid.
            */
     
            self::$collection[$this->internal_uuid] = $this;
        } 
     
        public function __destruct(){
            echo '*** FIN DU SCRIPT ***';
        }
    }
     
        //Après la déclaration de la classe, ben… on s'en sert.
    $oObject = Object::factory();
    unset($oObject);
    Le unset doit se trouver à la fin du code. Je pense que Php lit l'ensemble du code et le traite ensuite. Je ne sais pas si c'est cela mais il me semble bien.
    "Dites moi ce dont vous avez besoin, je vous apprendrai à vous en passer".
    Et de grâce, je ne possède pas le plugin boule de cristal de firefox, alors soyez clair dans vos questions.

    Je lutte contre le language SMS.

  3. #3
    Membre éclairé Avatar de metagoto
    Profil pro
    Hobbyist programmateur
    Inscrit en
    Juin 2009
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Hobbyist programmateur

    Informations forums :
    Inscription : Juin 2009
    Messages : 646
    Points : 845
    Points
    845
    Par défaut
    Citation Envoyé par Bilhackmac Voir le message
    Quelqu'un a-t-il une idée ? Je m'arrache les cheveux la dessus… j'ai essayé dans tous les sens avec référence, sans référence (bon même si elles sont implicite en PHP5)
    C'est tout à fait normal que ça ne se passe pas comme tu veux.
    self::$collection garde une référence vers ton objet. Quand tu fais ton unset, la référence de $oObject est détruite, mais pas celle dans self::$collection.

    Ton destructeur n'est donc appelé qu'à la toute fin du script, après le dernier echo.

    Ce qu'il faudrait faire, c'est briser la première référence avant le unset.
    Du genre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public function release() {
      self::$collection[$this->internal_uuid] = null;
    }
    Puis:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    $oObject = Object::factory();
    $oObject->release();
    unset($oObject);
    Note que tu ne peux pas mettre l'équivalent de release() dans le destructeur car ce destructeur n'est pas appelé par unset(), mais bien par php à la toute fin.

  4. #4
    Membre éprouvé Avatar de Herode
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2005
    Messages
    825
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2005
    Messages : 825
    Points : 933
    Points
    933
    Par défaut
    Non, mais on peut quand même faire d'une pierre deux couilles :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class Object {
       public static function delete(Object $o) {
             self::$collection[$o->internal_uuid] = null;
             unset($o);
       }
       ...
    }
    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $o = Object::factory();
    Object::delete($o);

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    merci de vos réponse mais ce n'est pas exactement ce que je cherche. Ce que je voudrais c'est détruire l'objet à partir d'une ce ses références quelque soit le nombre de référence.

    En partant de ma classe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    $ref_x = $ref_y = $ref_z = $oObject = Object::factory();
    unset($oObject);
     
    var_dump($ref_x);
    var_dump($ref_y);
    var_dump($ref_z);
    var_dump(Object::$collection[$uuid/*qui correspondrait à l'uuid de $oObject*/]);
     
    /* Sortie écran */
    NULL
    NULL
    NULL
    NULL

    Je ne sais pas si c'est réalisable en php5, s'il le faut je peux passé en php6.

  6. #6
    Expert éminent sénior
    Avatar de mathieu
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    10 235
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 10 235
    Points : 15 532
    Points
    15 532
    Par défaut
    Citation Envoyé par Bilhackmac Voir le message
    merci de vos réponse mais ce n'est pas exactement ce que je cherche. Ce que je voudrais c'est détruire l'objet à partir d'une ce ses références quelque soit le nombre de référence.
    je n'ai pas compris, avec ton exemple de code, tu aurais aimé avoir quel résultat ?

  7. #7
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
     
    class Object{
    	public static $collection;
    	protected $internal_uuid;
     
    	public static function factory($uuid = null){
    		if(isset(self::$collection[$uuid])){
    			return self::$collection[$uuid];
    		}else{
    			return new Object();
    		}
    	}
     
    	protected function __construct(){
    		$this->uuid();
    		/* Bon je vous copie pas tous le code mais en gros cette fonction affecte,
    		* vous l'aurai compris, un identifiant unique a $this->internal_uuid.
    		*/
     
    		self::$collection[$this->internal_uuid] = $this;
    	} 
     
    	public function __destruct(){
    		echo '__destruct';
    	}
    }
     
    $ref_x = $ref_y = $ref_z = $oObject = Object::factory();
    unset($oObject);
     
    var_dump($ref_x);
    var_dump($ref_y);
    var_dump($ref_z);
    var_dump(Object::$collection[$uuid/*qui correspondrait à l'uuid de $oObject*/]);
    Avec ce code, et sans faire un unset sur chaque référence, j'aimerai avoir une sortie écran du type

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    __destruct
    NULL
    NULL
    NULL
    NULL
    bien sur ce n'est pas ce que j'obtient actuellement


    [edit] je voudrai que mes références se comportent comme des pointeurs en C++ (si mes base de c++ sont bonnes)

  8. #8
    Membre éprouvé Avatar de Herode
    Homme Profil pro
    Développeur Web
    Inscrit en
    Mars 2005
    Messages
    825
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2005
    Messages : 825
    Points : 933
    Points
    933
    Par défaut
    C'est possible mais malheureusement pas avec la même écriture qu'en C++.
    La raison est présentée dans l'article du manuel sur les références :
    http://www.php.net/manual/fr/languag...references.php

    Autrement dit, pour obtenir le comportement que tu recherches, il faut recourir à une petite astuce d'écriture.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <?php
    class Objet{
        public $val = "aaa<br/>";
     
        public function __construct() {
            echo __METHOD__, "<br/>";
        }
     
        public function __destruct() {
            echo __METHOD__, "<br/>";
        }
     
        public function __toString() {
            return $this->val;
        }
    }
     
    $o = new Objet();
    $ref = &$o;
    $ref2 = &$ref;
    echo "1, $o, $ref, $ref2, <br/>";
    $o = null;
    echo "1, $o, $ref, $ref2, <br/>";
    echo "FIN SCRIPT";
    ?>
    qui donne bien comme sortie
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Objet::__construct
    1, aaa, aaa, aaa, 
    Objet::__destruct
    1, , , , 
    FIN SCRIPT
    Malheureusement, la surcharge d'opérateurs qui est possible en C++ n'est pas présente en PHP, donc il n'y a pas moyen (à ma connaissance) d'implémenter ça de manière transparente dans ta classe.

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    Un grand merci Herode, grâce à tes lumières je peux désormais supprimer un objet quelque soit la référence par lequel on veux le supprimer.

    J'ai tout de même dû modifier Object::factory car lors de la récupération d'un objet via Object::factory(<uuid de l'object>); il été impossible de supprimer cet objet via un unset ou un '= null'. Object::factory retourne donc systématiquement une référence du tableau statique Object::$collection au lieu de retourner 'new Object' dans le cas d'une création.


    Voici la classe modifiée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    class Object{
    	public $uuid;
     
    	private static $collection = array();
     
     
     
    	public static function &factory($uuid = null){
    		if($uuid != null && isset(self::$collection[$uuid])){
    			return self::$collection[$uuid];
    		}else{
    			$Object = new Object();
    			return self::$collection[$Object->uuid];
    		}
    	}
     
    	protected function __construct(){
    		$this->uuid();
     
    		self::$collection[$this->uuid] = $this;
    	}
     
    	public function __destruct(){
    		echo __METHOD__;
    	}
     
    	final protected function uuid(){
    		$md5 = md5(uniqid());
    		$this->uuid = substr($md5, 0, 8) .'-'. substr($md5, 8, 4) .'-'. substr($md5, 12, 4) .'-'. substr($md5, 16, 4) .'-'. substr($md5, 20, 12);
    	}
     
    	public static function delete(Object $Object) {
    		self::$collection[$Object->uuid] = null;
    	}
    }

    On crée trois références :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    $obj1 = &Object::factory();
    $obj2 = &Object::factory($obj1->uuid);
    $obj3 = &$obj1;
    Puis on fait les tests :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    /* Test 1 */
    Object::delete($obj1);
     
    /* Test 2 */
    Object::delete($obj2);
     
    /* Test 3 */
    Object::delete($obj3);
    Dans les 3 cas ont à bien $obj1 = $obj2 = $obj3 = null et Object::__destruct() est bien appelé après Object:delete();

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [POO] destruction d'objet ?
    Par karibouk dans le forum Général JavaScript
    Réponses: 10
    Dernier message: 21/01/2009, 11h36
  2. [POO] Destruction d'objet
    Par Kephuro dans le forum Langage
    Réponses: 6
    Dernier message: 07/06/2008, 01h24
  3. [POO] cloner un objet (et tous ses sous objets ?)
    Par Merfolk dans le forum Langage
    Réponses: 11
    Dernier message: 05/05/2008, 16h23
  4. Réponses: 4
    Dernier message: 29/11/2007, 01h52
  5. [POO] Destruction d'objet php
    Par krfa1 dans le forum Langage
    Réponses: 5
    Dernier message: 18/01/2007, 21h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo