Précédent   Forum des professionnels en informatique > PHP > Langage > Syntaxe
Syntaxe Forum d'entraide sur la syntaxe de PHP et la POO. Avant de poster -> FAQ syntaxe, Cours d'initiation et cours de POO
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 04/05/2008, 13h06   #1
Membre du Club
 
Avatar de Merfolk
 
Inscription : juillet 2003
Messages : 166
Détails du profil
Informations personnelles :
Âge : 32

Informations forums :
Inscription : juillet 2003
Messages : 166
Points : 59
Points : 59
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 :
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
Merfolk est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 04/05/2008, 16h13   #2
Membre éprouvé
 
Homme
Inscription : août 2006
Messages : 313
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 27
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

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

Informations forums :
Inscription : août 2006
Messages : 313
Points : 497
Points : 497
Il faut utiliser la methode magic __clone.

Voici un exemple de code qui marche.
Code :
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 />';
Phelim est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/05/2008, 12h06   #3
Membre Expert
 
Inscription : janvier 2007
Messages : 1 452
Détails du profil
Informations personnelles :
Âge : 27
Localisation : France, Paris (Île de France)

Informations forums :
Inscription : janvier 2007
Messages : 1 452
Points : 1 914
Points : 1 914
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
kaymak est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/05/2008, 12h31   #4
Membre du Club
 
Avatar de Merfolk
 
Inscription : juillet 2003
Messages : 166
Détails du profil
Informations personnelles :
Âge : 32

Informations forums :
Inscription : juillet 2003
Messages : 166
Points : 59
Points : 59
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 :
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
Merfolk est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/05/2008, 13h13   #5
Membre Expert
 
Inscription : janvier 2007
Messages : 1 452
Détails du profil
Informations personnelles :
Âge : 27
Localisation : France, Paris (Île de France)

Informations forums :
Inscription : janvier 2007
Messages : 1 452
Points : 1 914
Points : 1 914
Citation:
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.

Citation:
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.

Citation:
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.).


Citation:
je ne comprends pas cette ligne par exemple
$this ->pieces[$i] = clone $this ->pieces[$i];
On pourrait traduire cette ligne ainsi :
Code :
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
kaymak est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/05/2008, 13h32   #6
Membre éprouvé
 
Homme
Inscription : août 2006
Messages : 313
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 27
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

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

Informations forums :
Inscription : août 2006
Messages : 313
Points : 497
Points : 497
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.)
Phelim est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/05/2008, 13h58   #7
Membre du Club
 
Avatar de Merfolk
 
Inscription : juillet 2003
Messages : 166
Détails du profil
Informations personnelles :
Âge : 32

Informations forums :
Inscription : juillet 2003
Messages : 166
Points : 59
Points : 59
je voulais dire :
pour cloner un objet j'aurai eu tendance à écrire ça

Code :
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
Merfolk est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/05/2008, 14h11   #8
Membre Expert
 
Inscription : janvier 2007
Messages : 1 452
Détails du profil
Informations personnelles :
Âge : 27
Localisation : France, Paris (Île de France)

Informations forums :
Inscription : janvier 2007
Messages : 1 452
Points : 1 914
Points : 1 914
Hm bien vu. Et sa explique mieu tes interrogations.

bref :
Code :
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
kaymak est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/05/2008, 14h17   #9
Membre du Club
 
Avatar de Merfolk
 
Inscription : juillet 2003
Messages : 166
Détails du profil
Informations personnelles :
Âge : 32

Informations forums :
Inscription : juillet 2003
Messages : 166
Points : 59
Points : 59
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 ?
Merfolk est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/05/2008, 14h34   #10
Membre éprouvé
 
Homme
Inscription : août 2006
Messages : 313
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 27
Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

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

Informations forums :
Inscription : août 2006
Messages : 313
Points : 497
Points : 497
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
Phelim est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/05/2008, 14h41   #11
Membre Expert
 
Inscription : janvier 2007
Messages : 1 452
Détails du profil
Informations personnelles :
Âge : 27
Localisation : France, Paris (Île de France)

Informations forums :
Inscription : janvier 2007
Messages : 1 452
Points : 1 914
Points : 1 914
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 :
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 :
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é
kaymak est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 05/05/2008, 16h23   #12
Membre du Club
 
Avatar de Merfolk
 
Inscription : juillet 2003
Messages : 166
Détails du profil
Informations personnelles :
Âge : 32

Informations forums :
Inscription : juillet 2003
Messages : 166
Points : 59
Points : 59
bon j'ai réussi à faire,

c'est bien comme ça que ça se passe
Citation:
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 :
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 :
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
 
******* 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
)
Merfolk est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 00h40.


 
 
 
 
Partenaires

Hébergement Web