我在
PHP中有一个面向对象的父子树,我想要克隆.
困难的部分是对树的访问并不总是通过根,但有时通过根的子进程,如下所示:
[Root]
-- [Element1] START CLONE
-- [Element3]
-- [Element4]
-- [Element2]
-- [Element5]
所以我想做的是克隆整个树,通过调用$new = clone $element1;
__clone()方法声明还必须克隆每个子节点,并且,如果出现图示的情况*,则还必须克隆父节点.
* Root在Element1中显式设置为父级,因此系统可以识别这种情况并对其执行某些操作.
问题是,从Element1开始克隆操作时,还必须克隆Root. Root的克隆过程规定必须克隆所有子元素,因此再次调用Element1的克隆操作,然后重复相同的克隆过程,产生无限循环.
此外,Root不会包含Element1的第一个克隆,但它会生成自己的克隆以作为子元素添加.然后,Element1将Root作为其父级,但Root将不具有与子级相同的Element1.
我希望我能以清晰的方式提出问题,有人可以帮我找到解决方案.
编辑:
最终解决方案
/**
* The $replace and $with arguments allow a custom cloning procedure. Instead of
* being cloned, the original child $replace will be replaced by $with.
*/
public function duplicate($replace = null, $with = null) {
// Basic cloning
$clone = clone $this;
// If parent is set
if(isset($this->parent)) {
// Clone parent, replace this element by its clone
$parentClone = $this->parent->duplicate($this, $clone);
$clone->parent = $parentClone;
}
// Remove all children in the clone
$clone->clear();
// Add cloned children from original to clone
foreach($this->getChildren() as $child) {
if($child === $replace)
// If cloning was initiated from this child, replace with given clone
$childClone = $with;
else
// Else duplicate child normally
$childClone = $child->duplicate();
// Add cloned child to this clone
$clone->add($childClone);
}
return $clone;
}
最佳答案 首先,简化您的示例:
[Root]
-- [Element1] START CLONE
-- [Element3]
然后你做的不同,我认为你有三个操作
>公共克隆方法.
>自我克隆操作,返回带子节点的克隆,但不返回父节点.
>单克隆操作,返回没有子节点的克隆.
类之外的代码使用公共克隆方法.但是__clone()方法不能使用该方法,否则会遇到您所描述的循环循环问题.所以__clone()实现必须使用其他方法.
将cloneSelf和cloneSingle方法添加到您的类中,使它们受到保护,因此继承的类可以调用它们,但它们不公开.
然后在__clone()实现中使用它们:
public function clone()
{
// clone the parent
$parent = $this->getParent();
$parentClone = $parent->cloneSingle();
// clone all children of parent which includes $this
$selfClone = NULL;
foreach($parent->getChildren() as $child)
{
$childClone = $child->cloneSelf();
if (!$selfClone && $child === $this)
$selfClone = $childClone;
$parentClone->addChild($childClone);
}
assert('$selfClone');
return $selfClone;
}
public function __clone()
{
$message = 'Clone operator is not allowed, use clone() method instead.';
throw new BadMethodCallException($message);
}
这些方法还可以帮助您在没有父级的情况下进行克隆.