Quelqu'un peut-il m'expliquer
qu'est-ce que le clonage d'objets en php?
Quand dois-je utiliser le mot-clé clone dans php?
Le clonage d'objet est l'acte de faire une copie d'un objet. Comme Cody l'a souligné, le clonage en PHP se fait en faisant une copie superficielle de l'objet. Cela signifie que les objets internes de l'objet cloné seront ne pas être cloné, sauf si vous demandez explicitement à l'objet de cloner également ces objets internes, en définissant la méthode magique __clone()
.
Si vous n'utilisez pas le __clone
, les objets internes du nouvel objet seront des références aux mêmes objets en mémoire que les objets internes de l'objet d'origine qui a été cloné.
Considérez ces exemples:
// in this exampe the internal member $_internalObject of both objects
// reference the same instance of stdClass in memory.
class CloneableClass
{
private $_internalObject;
public function __construct()
{
// instantiate the internal member
$this->_internalObject = new stdClass();
}
}
$classA = new CloneableClass();
$classB = clone $classA;
// in this exampe the internal member $_internalObject of both objects
// DON'T reference the same instance of stdClass in memory, but are inividual instances
class CloneableClass
{
private $_internalObject;
public function __construct()
{
// instantiate the internal member
$this->_internalObject = new stdClass();
}
// on clone, make a deep copy of this object by cloning internal member;
public function __clone()
{
$this->_internalObject = clone $this->_internalObject;
}
}
$classA = new CloneableClass();
$classB = clone $classA;
Les cas d'utilisation pour le clonage seraient par exemple un cas où vous ne voulez pas que des objets extérieurs gâchent l'état interne d'un objet.
Disons que vous avez un utilisateur de classe avec une adresse d'objet interne.
class Address
{
private $_street;
private $_streetIndex;
private $_city;
// etc...
public function __construct( $street, $streetIndex, $city /* etc.. */ )
{
/* assign to internal values */
}
}
class User
{
// will hold instance of Address
private $_address;
public function __construct()
{
$this->_address = new Address( 'somestreet', '1', 'somecity' /* etc */ );
}
public function getAddress()
{
return clone $this->_address;
}
}
Pour des raisons d'argument, disons que vous ne voulez pas que des objets extérieurs fouillent avec l'adresse interne des objets utilisateur, mais vous voulez pouvoir leur donner une copie de l'objet adresse. L'exemple ci-dessus illustre cela. La méthode getAddress
renvoie un clone de l'objet adresse aux objets appelants. Cela signifie que si l'objet appelant modifie l'objet Adresse, l'adresse interne de l'utilisateur ne changera pas. Si vous n'avez pas donné de clone, l'objet extérieur pourrait modifier l'adresse interne de l'utilisateur, car une référence est donnée par défaut, pas un clone.
J'espère que tout cela a du sens.
PS.:
Sachez cependant que si Address aurait également des objets internes, vous devez vous assurer que Address se copie en profondeur lors du clonage (comme dans mon deuxième exemple de cet article) en définissant __clone()
dans Adresse. Sinon, vous aurez des maux de tête en essayant de comprendre pourquoi vos données sont vissées.
Le clonage est utilisé pour créer une copie authentique d'un objet. L'affectation d'un objet à une autre variable ne crée pas de copie - elle crée plutôt une référence au même emplacement mémoire que l'objet:
<?php
$o= new stdclass;
$o->a= 'b';
$o->b= 'c';
$o2= $o;
$o2->a= 'd';
var_dump($o);
var_dump($o2);
$o3= clone $o;
$o3->a= 'e';
var_dump($o);
var_dump($o3);
?>
Cet exemple de code affichera les éléments suivants:
object(stdClass)#1 (2) {
["a"]=>
string(1) "d"
["b"]=>
string(1) "c"
}
object(stdClass)#1 (2) {
["a"]=>
string(1) "d"
["b"]=>
string(1) "c"
}
object(stdClass)#1 (2) {
["a"]=>
string(1) "d"
["b"]=>
string(1) "c"
}
object(stdClass)#2 (2) {
["a"]=>
string(1) "e"
["b"]=>
string(1) "c"
}
Le clonage d'objet, en termes de PHP 5, est ce qu'on appelle un "copie superficielle" . Il appelle ensuite la méthode __clone () sur l'objet cloné.
Si vous avez besoin d'un clone profond - c'est-à-dire des clones des objets enfants et des clones des petits-enfants - vous pouvez soit écraser __clone
dans chacune des classes, ou simplement sérialiser + désérialiser l'objet:
function deepClone($object)
{
return unserialize(serialize($object));
}
Comme expliqué dans d'autres réponses, clone
crée une copie superficielle de l'objet.
Si vous devez créer une copie complète (c'est-à-dire une copie récursive), vous pouvez surcharger les méthodes __clone()
.
Vous pouvez également utiliser cette bibliothèque: MyCLabs\DeepCopy, qui est plus simple et plus puissant qu'un simple clone.