web-dev-qa-db-fra.com

qu'est-ce que le clonage d'objets en php?

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?

40
user213559

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.

40
Decent Dabbler

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"
}
27
leepowers

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é.

7
Cody Haines

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));
}
6
cweiske

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.

1
Matthieu Napoli