Comment créer une copie d'un objet en PHP?
Il semble qu'en PHP les objets soient passés par référence. Même les opérateurs d'affectation ne semblent pas créer une copie de l'objet.
Voici une preuve simple et artificielle:
<?php
class A {
public $b;
}
function set_b($obj) { $obj->b = "after"; }
$a = new A();
$a->b = "before";
$c = $a; //i would especially expect this to create a copy.
set_b($a);
print $a->b; //i would expect this to show 'before'
print $c->b; //i would ESPECIALLY expect this to show 'before'
?>
Dans les deux cas d'impression, je reçois 'après'
Donc, comment puis-je passer $a pour set_b() par valeur et non par référence?
9 réponses
En PHP 5 + les objets sont passés par référence. En PHP 4, ils sont passés par valeur (c'est pourquoi il avait un passage d'exécution par référence, qui est devenu obsolète).
Vous pouvez utiliser L'opérateur' clone ' dans PHP5 pour copier des objets:
$objectB = clone $objectA;
En outre, ce ne sont que des objets qui sont passés par référence, pas tout comme vous l'avez dit dans votre question...
Les réponses se trouvent généralement dans les livres Java.
Le Clonage: Si vous ne remplacez pas la méthode clone, le comportement par défaut est shallow copy. Si vos objets n'ont que des variables membres primitives, c'est totalement ok. Mais dans un langage sans type avec un autre objet en tant que variables membres, c'est un casse-tête.
La Sérialisation/désérialisation
$new_object = unserialize(serialize($your_object))
Cela permet d'obtenir une copie profonde avec un coût élevé en fonction de la complexité de l'objet.
Selon le commentaire précédent, si vous avez un autre objet en tant que variable membre, procédez comme suit:
class MyClass {
private $someObject;
public function __construct() {
$this->someObject = new SomeClass();
}
public function __clone() {
$this->someObject = clone $this->someObject;
}
}
Maintenant, vous pouvez faire le clonage:
$bar = new MyClass();
$foo = clone $bar;
Selon les docs (http://ca3.php.net/language.oop5.cloning):
$a = clone $b;
Juste pour clarifier PHP utilise copy on write, donc fondamentalement tout est une référence jusqu'à ce que vous le Modifiez, mais pour les objets, vous devez utiliser clone et la méthode magique __clone() comme dans la réponse acceptée.
CE Code aide les méthodes de clone
class Foo{
private $run=10;
public $foo=array(2,array(2,8));
public function hoo(){return 5;}
public function __clone(){
$this->boo=function(){$this->hoo();};
}
}
$obj=new Foo;
$news= clone $obj;
var_dump($news->hoo());
Je faisais des tests et j'ai eu ceci:
class A {
public $property;
}
function set_property($obj) {
$obj->property = "after";
var_dump($obj);
}
$a = new A();
$a->property = "before";
// Creates a new Object from $a. Like "new A();"
$b = new $a;
// Makes a Copy of var $a, not referenced.
$c = clone $a;
set_property($a);
// object(A)#1 (1) { ["property"]=> string(5) "after" }
var_dump($a); // Because function set_property get by reference
// object(A)#1 (1) { ["property"]=> string(5) "after" }
var_dump($b);
// object(A)#2 (1) { ["property"]=> NULL }
var_dump($c);
// object(A)#3 (1) { ["property"]=> string(6) "before" }
// Now creates a new obj A and passes to the function by clone (will copied)
$d = new A();
$d->property = "before";
set_property(clone $d); // A new variable was created from $d, and not made a reference
// object(A)#5 (1) { ["property"]=> string(5) "after" }
var_dump($d);
// object(A)#4 (1) { ["property"]=> string(6) "before" }
?>
Dans cet exemple, nous allons créer iPhone classe et de faire la copie exacte de celui-ci par clonage
class iPhone {
public $name;
public $email;
public function __construct($n, $e) {
$this->name = $n;
$this->email = $e;
}
}
$main = new iPhone('Dark', 'm@m.com');
$copy = clone $main;
// if you want to print both objects, just write this
echo "<pre>"; print_r($main); echo "</pre>";
echo "<pre>"; print_r($copy); echo "</pre>";
Si vous souhaitez copier entièrement les propriétés d'un objet dans une instance différente, vous pouvez utiliser cette technique:
Sérialisez-le en JSON, puis désérialisez-le en objet.