如何在PHP中clone
对象包含所有数据?
所以,澄清:"包含所有整个数据"意味着我需要真正复制实例中的任何对象。例如,如果您有:
class Bar
{
public $indicator;
public function __construct($x)
{
$this->indicator = $x;
}
}
class Foo
{
protected $prop;
public function __construct(Bar $prop)
{
$this->prop = $prop;
}
public function getProp()
{
return $this->prop;
}
}
$objX = new Foo(new Bar('one'));
$objY = clone $objX;
$objY->getProp()->indicator = 'two';
//two, since cloned object still tracks references inside it:
echo $objX->getProp()->indicator;
上面代码的小提琴你可以找到here。
没关系......
因为标准__clone()
只会复制主对象本身:
当克隆一个对象时,PHP 5将执行所有的浅层副本 对象的属性。任何引用其他的属性 变量,仍然是参考。
所以它不会跟踪内部的所有实体,因为它会非常慢。但现在,我需要这样做。
用例是:当我测试我的代码时,我正在为phpunit的可调用匹配器提供值存储。但是,该存储是方法名称,参数值和结果值之间的简单映射。一切都很好,除非我需要两次使用相同的map值 - 因为在下一次迭代时它可能会被测试的代码修改。这是一个问题。
天真的方法
到目前为止,我做到了这一点:
public static function cloneArrayContainer(array $data)
{
$result = [];
foreach ($data as $key => $value) {
if (is_object($value)) {
$result[$key] = self::cloneObjectContainer($value);
} else if (is_array($value)) {
$result[$key] = self::cloneArrayContainer($value);
} else {
$result[$key] = $value;
}
}
return $result;
}
public static function cloneObjectContainer($object)
{
$result = clone $object;
$reflection = new \ReflectionObject($object);
foreach ($reflection->getProperties() as $property) {
$property->setAccessible(true);
$value = $property->getValue($result);
if (is_object($value)) {
$property->setValue($result, self::cloneObjectContainer($value));
} elseif (is_array($value)) {
$property->setValue($result, self::cloneArrayContainer($value));
}
}
return $result;
}
在一个存根助手中。但它在循环引用(显然)上失败了,遗憾的是,在我的情况下无法避免,因为它们对我的应用程序是有效的(并且是业务逻辑要求的)对象。
有什么想法吗?
我也试过unserialize()
/ serialize()
- 失败了,而且,我的对象里面可能有callables / resources,因此,一种方法不适合我的情况。目前,我正在考虑重新考虑结构本身(测试,我的意思) - 但这将是最后一件事,这意味着克隆方法失败。