I'm having a blonde moment with __clone()
Posted: Fri Jul 20, 2007 10:04 am
Trying to clone an object which contains other objects. I need these other objects to be cloned too so I'm using __clone(). The problem I'm having is that I have a property which is an array of references to other objects. Some of these reference exactly the same object and I need to ensure that when I clone a reference, anything which also referenced the original object now references the clone instead.
I'll try to give a simplified example:
Any clues?
I tried this but it doesn't seem to work:
EDIT | Typo
Test case for anyone up for a challenge:

I'll try to give a simplified example:
Code: Select all
class MyClass {
public $references = array();
public function addReference($key, $obj) {
$this->references[$key] = $obj; //This is done by reference in PHP5!
}
public function __clone() {
//I need to clone $this->references too, but keeping the duplicates in tact
}
}
$o = new MyClass();
$o->addReference("foo", $obj1);
$o->addReference("bar", $obj2);
$o->addReference("zip", $obj1); //This points to the same object as foo!!
//$o->references["foo"] and $o->references["zip"] reference the same object
$o2 = clone $o;
//How do I make sure $o2->references["foo"] and $o2->references["zip"] reference the same object
// But still make sure they have been cloned out of $o ??I tried this but it doesn't seem to work:
Code: Select all
public function __clone() {
$tracker = null;
$add = null;
foreach ($this->references as $k => $obj) {
if ($obj !== $tracker) {
$tracker = $obj;
$add = clone $obj;
}
$this->references[$k] = $add;
}
}Test case for anyone up for a challenge:
Code: Select all
<?php
error_reporting(E_ALL);
ini_set("display_errors", true);
require_once "/home/d11wtq/PHPLibs/simpletest/unit_tester.php";
require_once "/home/d11wtq/PHPLibs/simpletest/reporter.php";
class MyClass {
public $references = array();
public function addReference($key, $obj) {
$this->references[$key] = $obj; //This is done by reference in PHP5!
}
public function __clone() {
$tracker = null;
$add = null;
foreach ($this->references as $k => $obj) {
if ($obj !== $tracker) {
$tracker = $obj;
$add = clone $obj;
}
$this->references[$k] = $add;
}
}
}
class X {}
class Y {}
class TestOfClone extends UnitTestCase
{
public function testClone()
{
$x = new X();
$y = new Y();
$o = new MyClass();
$o->addReference("foo", $x);
$o->addReference("bar", $y);
$o->addReference("zip", $x);
$this->assertReference($o->references["foo"], $o->references["zip"]);
$o2 = clone $o;
$this->assertCopy($o->references["foo"], $o2->references["foo"]);
$this->assertCopy($o->references["bar"], $o2->references["bar"]);
$this->assertCopy($o->references["zip"], $o2->references["zip"]);
$this->assertReference($o2->references["foo"], $o2->references["zip"]);
}
}
$test = new TestOfClone();
$test->run(new HtmlReporter());EDIT | Test case updated to avoid cheatersTestOfClone
Fail: testClone -> [Object: of X] and [Object: of X] should reference the same object at [/home/d11wtq/public_html/TestClone.php line 48]
1/1 test cases complete: 4 passes, 1 fails and 0 exceptions.