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] cloner un objet (et tous ses sous objets ?)


Sujet :

Langage PHP

  1. #1
    Membre régulier Avatar de Merfolk
    Profil pro
    Inscrit en
    Juillet 2003
    Messages
    170
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Juillet 2003
    Messages : 170
    Points : 113
    Points
    113
    Par défaut [POO] cloner un objet (et tous ses sous objets ?)
    Hello


    j'ai des difficultés à utiliser la méthode clone... mon but est de dupliquer un objet "full" , dupliquer aussi tous les objets qu'il contient, et encore chaque sous objet, et sous sous objet...

    j'y arrive en faisant un serialize/ unserialize, mais je pense que c'est peut être un goulot d'étranglement.

    J'ai vu qu'il y avait une méthode clone...mais je ne comprends pas comment elle marche.


    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
     
     
    // recupere un autre objet jeu
    function cloner()
    {
    		/* fonctionne */
     		$nouveauJeu=new jeu(false);
    		$tmp=serialize($this->listePieces);
    		$nouveauJeu->chargerPieces($tmp); // fait $this->listePieces = unserialize..
    		return $nouveauJeu;
     
     
                    /* ne fonctionne pas, les sous objets ne sont pas clonés apparement */
    		return clone($this);
     
                    // $this->listePieces est un tableau d'un autre objet, Piece, qui lui aussi contient pleins d'autres objets...
    }


    merci

  2. #2
    Membre confirmé

    Homme Profil pro
    Inscrit en
    Août 2006
    Messages
    317
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2006
    Messages : 317
    Points : 597
    Points
    597
    Par défaut
    Il faut utiliser la methode magic __clone.

    Voici un exemple de code qui marche.
    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
    37
    38
    39
    40
    41
    42
    43
     
    class jeu{
        public $pieces;
        public function chargerPieces($a_piece){
            $this -> pieces = $a_piece;
        }
     
        public function __clone() 
        {  
           $size = count($this -> pieces);
           for($i=0; $i<$size; $i++){
                $this ->pieces[$i] = clone $this ->pieces[$i];
           }
        }
    }
     
    class piece{
        public $valeur;
        public function __construct($valeur){
            $this -> valeur = $valeur;
        }
    }
     
    $pieces = array();
    $pieces[] = new piece('carte rouge');
    $pieces[] = new piece('carte bleu');
    $pieces[] = new piece('carte bleu');
     
    $jeu = new jeu();
    $jeu -> chargerPieces($pieces);
    $jeu2 = clone $jeu;
     
    var_dump($jeu);
    echo '<br /><br /><br />';
    var_dump($jeu2);
    echo '<br /><br /><br />';
     
    $jeu2-> pieces[1] -> valeur = 'fausse carte';
     
    var_dump($jeu);
    echo '<br /><br /><br />';
    var_dump($jeu2);
    echo '<br /><br /><br />';

  3. #3
    Membre émérite
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 448
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 448
    Points : 2 284
    Points
    2 284
    Par défaut
    En complément je dirais que la méthode __clone qui est défnis dans tes classes est la méthode qui est appelée par PHP lorsque tu appelles la fonction clone ainsi :
    clone($toto);
    ou $toto est une instance d'une classe.

    Si tu ne définis pas cette méthode, j'imagine que PHP clone l'objet sans cloner les objets à l'intérieur, et fais donc des références.

    tu fera attention, on parle bien de la méthode __clone et de la fonction clone, qui sont toutes deux différentes.

    voiilà, simple précision.

    bye

  4. #4
    Membre régulier Avatar de Merfolk
    Profil pro
    Inscrit en
    Juillet 2003
    Messages
    170
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Juillet 2003
    Messages : 170
    Points : 113
    Points
    113
    Par défaut
    ok

    juste un précision :
    si je comprends bien je dois aussi définir __clone dans piece pour tous ses objets, et ainsi de suite ?

    sinon j'avoue j'ai du mal à comprendre le code là
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public function __clone() 
        {  
           $size = count($this -> pieces);
           for($i=0; $i<$size; $i++){
                $this ->pieces[$i] = clone $this ->pieces[$i];
           }
        }
    c'est une méthode qui est appelée par qui ?
    par le nouvel objet ? ou l'ancien ?

    enfin si je compare à c++ les constructeurs de recopie tout ça, ben il manque un parametre là, non ? quel est le nouvel objet, quel est "la source" ?
    je ne comprends pas cette ligne par exemple
    $this ->pieces[$i] = clone $this ->pieces[$i];


    merci

  5. #5
    Membre émérite
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 448
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 448
    Points : 2 284
    Points
    2 284
    Par défaut
    juste un précision :
    si je comprends bien je dois aussi définir __clone dans piece pour tous ses objets, et ainsi de suite ?
    Oui.

    c'est une méthode qui est appelée par qui ?
    par le nouvel objet ? ou l'ancien ?
    Pour ce que j'en sais, aucun des deux, c'est PHP qui prend en charge la duplication et qui execute les appels à la méthode __clone lorsqu'elle est définie. Dans le cas contraire PHP utilise sa propre méthode de clonage.

    enfin si je compare à c++ les constructeurs de recopie tout ça, ben il manque un parametre là, non ? quel est le nouvel objet, quel est "la source" ?
    Je ne connais pas C++, mais d'après ce que j'ai lu, ce langage dispose de trois types de ctors. En PHP il n'y en à qu'un, et pour cloner c'est la méthode dite *magic* qui est appelé. en l'occiurence __clone. L'objet source c'est this car c'est une méthode d'instance. Le nouvel objet c'est ce que la méthode retourne (Au passage, je ne sais pas si PHP émet un warning si on renvoi un type différent.).


    je ne comprends pas cette ligne par exemple
    $this ->pieces[$i] = clone $this ->pieces[$i];
    On pourrait traduire cette ligne ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $this ->pieces[$i] = $this ->pieces[$i]->__clone();
    Si la méthode __clone est définie, bien sûr.

    en espérant que cela t'aides à saisir.

    bye

  6. #6
    Membre confirmé

    Homme Profil pro
    Inscrit en
    Août 2006
    Messages
    317
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2006
    Messages : 317
    Points : 597
    Points
    597
    Par défaut
    Les methodes *magic* de php pour les objets sont des methodes dont normalement tu n'as pas à faire l'appel directement.
    Elles reagissent à des evenements.

    Voici quelques exemples :
    __construct : methode appellé a la creation d'un objet
    __get : methode appellé quand on effectue un appel à un attribut inexistant. $objet ->mavariable (sauf que mavariable n'existe pas)
    __set : methode appellé quand on effectue une assignation de valeur à un attribut indexistant ($objet -> mavariable = 1)
    __clone : methode appellé lors du clonage et indiquant les actions specifiques à effectuer en plus du clonage de l'objet (par exemple, cloner tous les attributs si ce sont des objets, tu peux utiliser l'API de reflexion de PHP pour faire ça.)

  7. #7
    Membre régulier Avatar de Merfolk
    Profil pro
    Inscrit en
    Juillet 2003
    Messages
    170
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Juillet 2003
    Messages : 170
    Points : 113
    Points
    113
    Par défaut
    je voulais dire :
    pour cloner un objet j'aurai eu tendance à écrire ça

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public function __clone($source) 
    {  
           $size = count($source -> pieces);
           for($i=0; $i<$size; $i++)
           {
                $this ->pieces[$i] = clone $source->pieces[$i];
           }
      }
    si je reprends ton exemple :

    public function __clone()
    {
    $size = count($this -> pieces);
    for($i=0; $i<$size; $i++){
    $this ->pieces[$i] = clone $this ->pieces[$i];
    }
    }


    dans ce cas le this signifie le nouvel objet et dans celui là l'ancien ? Comment on s'en sort ? je ne comprends pas


    [Edit :]

    ok je crois que je viens de comprendre le mécanisme....
    en fait
    1) l'objet est cloné automatiquement par php
    2) la méthode __clone est appelée sur le nouvel objet, et "this" reference le nouvel objet
    3) on boucle sur ce qu'on a, qui est donc ce que l'autre objet avait, car ça a déjà copié
    et on modifie ce qu'on a, en faisant pointer ailleurs, "ailleurs" étant, une copie de l'objet que l'on fabrique à la volée

  8. #8
    Membre émérite
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 448
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 448
    Points : 2 284
    Points
    2 284
    Par défaut
    Hm bien vu. Et sa explique mieu tes interrogations.

    bref :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public function __clone() 
    {
    $retour = new Jeu();  
           $size = count($this-> pieces);
           for($i=0; $i<$size; $i++)
           {
                $retour->pieces[$i] = clone $this->pieces[$i];
           }
    return $retour;
      }
    bye

  9. #9
    Membre régulier Avatar de Merfolk
    Profil pro
    Inscrit en
    Juillet 2003
    Messages
    170
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Juillet 2003
    Messages : 170
    Points : 113
    Points
    113
    Par défaut
    aïe, c'est contradictoire avec ce que je viens de déduire
    il faut un arbitre ^^

    clone est censé faire un return ou pas ?

  10. #10
    Membre confirmé

    Homme Profil pro
    Inscrit en
    Août 2006
    Messages
    317
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2006
    Messages : 317
    Points : 597
    Points
    597
    Par défaut
    Tu viens de mettre la main dans l'engrenage des methodes magic de PHP...
    Elles sont assez mal défini ^^ et surtout, on sait pas ce qu'il y'a derriere ... (La documentation est tres tres light à leur sujet)

    Personnellement, j'en sais rien. A dire vrai, je clone tres rarement mes objets et dans tous les cas, j'ai jamais eu à cloner un objet composé d'autres objets.

    Neanmoins, si tu fais des tests, les resultats m'interessent

  11. #11
    Membre émérite
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    1 448
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 1 448
    Points : 2 284
    Points
    2 284
    Par défaut
    Hm, bon après quelques test je me rends compte que j'ai dit des bétises....

    Mais la doc est quand même sacrément mal faites.

    Bref, un petit script pour comprendre.
    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
     
    <?
    class a
    {
    	public $z;
     
    	public function __construct()
    	{
    		$this->z = rand();
    	}
     
    	public function __clone( )
    	{
    		$retour = new a();
    		$retour->z = "r";
    		$this->z = rand();
     
    		echo "<pre>";
    		echo "Les arguments<br />";
    		var_dump(func_get_args());
    		echo "</pre>";
     
    		echo "<pre>";
    		echo "L'objet courant<br />";
    		var_dump($this);
    		echo "</pre>";
     
    		echo "<pre>";
    		echo "L'objet retour<br />";
    		var_dump($retour);
    		echo "</pre>";
     
    		return $retour;
    		return "Cette fonction est elle muette ?";
     
    	}
    }
     
    $test = new a();
     
    echo "<pre>";
    echo "L'objet original<br />";
    var_dump($test);
    echo "</pre>";
    $test_clone = clone($test);
     
    echo "<pre>";
    echo "L'objet cloné<br />";
    var_dump($test_clone);
    echo "</pre>";
     
     
    echo "<pre>";
    echo "L'objet original<br />";
    var_dump($test);
    echo "</pre>";
    ?>
    Qui nous résulte ceci :
    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
     
    L'objet original
    object(a)#1 (1) {
      ["z"]=>
      int(720)
    }
     
    Les arguments
    array(0) {
    }
     
    L'objet courant
    object(a)#2 (1) {
      ["z"]=>
      int(24014)
    }
     
    L'objet retour
    object(a)#3 (1) {
      ["z"]=>
      string(1) "r"
    }
     
    L'objet cloné
    object(a)#2 (1) {
      ["z"]=>
      int(24014)
    }
     
    L'objet original
    object(a)#1 (1) {
      ["z"]=>
      int(720)
    }
    donc, __clone est muette. Le return n'à pas d'effet. Il n'y à pas de source (:s c'est très étrange sa...) puisque les arguments sont vides. L'objet courant est l'objet résultat de l'appel à la fonction clone.

    Tout cela me fait dire qu'en fait, cette méthode est à priori relativement useless de mon point de vue.

    bye et désolé pour les boulettes :s Quoique thread tout de même interessant pour le point soulevé

  12. #12
    Membre régulier Avatar de Merfolk
    Profil pro
    Inscrit en
    Juillet 2003
    Messages
    170
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : France

    Informations forums :
    Inscription : Juillet 2003
    Messages : 170
    Points : 113
    Points
    113
    Par défaut
    bon j'ai réussi à faire,

    c'est bien comme ça que ça se passe
    1) l'objet est cloné automatiquement par php
    2) la méthode __clone est appelée après sur le nouvel objet, et "this" reference le nouvel objet
    3) on boucle sur ce qu'on a, qui est donc ce que l'autre objet avait, car ça a déjà copié
    et on modifie ce qu'on a, en faisant pointer ailleurs, "ailleurs" étant, une copie de l'objet que l'on fabrique à la volé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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
     
    <?
     
    //---------------------- debug ----------------------
    function d($var)
    {
    	print("<pre>");
    	print_r($var);
    	print("</pre>");
     
    }
     
    //---------------------- jeu ----------------------
    class Jeu
    {
    	var $listePieces;
    	var $nom;
     
    	function Jeu($nom)
    	{
    		$this->nom = $nom;
    	}
     
    	function ajouterPiece(Piece $p)
    	{
    		$this->listePieces[] = $p;
    	}
     
    	function __clone()
    	{
    		$this->nom = "je suis le clone";
    		for($i = 0 ; $i < count($this->listePieces) ; ++$i)
    		{
    			$this->listePieces[$i] = clone $this->listePieces[$i];
    		}
    	}
     
    }
     
     
    //---------------------- piece ----------------------
    class Piece
    {
    	var $nom;
    	var $coord;
    	function Piece($nom)
    	{
    		$this->nom = $nom;
    		$this->coord = new Coord(1,1);
    	}
     
    	function setNom($newNom)
    	{
    		$this->nom = $newNom;
    	}
     
    	function setCoord($x,$y)
    	{
    		$this->coord->setCoord($x,$y);
    	}
     
    	function __clone()
    	{
    		$this->nom = "je suis un {$this->nom} cloné";
    		$this->coord = clone $this->coord;
    	}
    }
     
     
     
    //---------------------- coord ----------------------
    class Coord
    {
    	var $x;
    	var $y;
    	var $nom;
    	function Coord($x,$y)
    	{
    		$this->x = $x;
    		$this->y = $y;
    		$this->nom = "coord";
    	}
     
    	function setCoord($x,$y)
    	{
    		$this->x = $x;
    		$this->y = $y;
    	}
     
    	function __clone()
    	{
    		$this->nom = "je suis une {$this->nom} clonée";
    	}
    }
     
     
    //---------------------- main ----------------------
     
    // construction jeu intial
    $objJeu = new Jeu("chess");
    $objFou = new Piece("fou");
    $objJeu->ajouterPiece($objFou);
     
    //clone 
    $objJeuClone = clone $objJeu;
     
     
    // test
    d("******* apres clonage initial *******");
    d($objJeu);
    d($objJeuClone);
     
    // modif fou
    $objFou->setCoord(2,2);
     
    // test
    d("******* apres modif fou *******");
    d($objJeu);
    d($objJeuClone);
     
     
     
     
    ?>
    donne en résultat
    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
     
    ******* apres clonage initial *******
     
    Jeu Object
    (
        [listePieces] => Array
            (
                [0] => Piece Object
                    (
                        [nom] => fou
                        [coord] => Coord Object
                            (
                                [x] => 1
                                [y] => 1
                                [nom] => coord
                            )
     
                    )
     
            )
     
        [nom] => chess
    )
     
    Jeu Object
    (
        [listePieces] => Array
            (
                [0] => Piece Object
                    (
                        [nom] => je suis un fou cloné
                        [coord] => Coord Object
                            (
                                [x] => 1
                                [y] => 1
                                [nom] => je suis une coord clonée
                            )
     
                    )
     
            )
     
        [nom] => je suis le clone
    )
     
    ******* apres modif fou *******
     
    Jeu Object
    (
        [listePieces] => Array
            (
                [0] => Piece Object
                    (
                        [nom] => fou
                        [coord] => Coord Object
                            (
                                [x] => 2
                                [y] => 2
                                [nom] => coord
                            )
     
                    )
     
            )
     
        [nom] => chess
    )
     
    Jeu Object
    (
        [listePieces] => Array
            (
                [0] => Piece Object
                    (
                        [nom] => je suis un fou cloné
                        [coord] => Coord Object
                            (
                                [x] => 1
                                [y] => 1
                                [nom] => je suis une coord clonée
                            )
     
                    )
     
            )
     
        [nom] => je suis le clone
    )

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

Discussions similaires

  1. Cloner un panel avec tous ses objets
    Par rdemont dans le forum ASP.NET
    Réponses: 3
    Dernier message: 11/07/2010, 21h33
  2. Réponses: 3
    Dernier message: 03/02/2009, 10h54
  3. Lister un répertoire et tous ses sous répertoires dans un treeview
    Par shaun_the_sheep dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 29/09/2008, 08h37
  4. Copier un dossier dans un répertoire et tous ses sous répertoires
    Par Aiacciu dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 07/01/2008, 21h24

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