PHP克隆父子树,从child开始,避免无限递归
我有一个 PHP 中的面向对象的父子树,我想克隆它。 困难的部分是对树的访问并不总是通过根,而是有时通过根的子级,如下所示:
[Root]
-- [Element1] START CLONE
-- [Element3]
-- [Element4]
-- [Element2]
-- [Element5]
所以我想做的是通过调用 来克隆整个树$new = clone $element1;
__clone() 方法指出,每个子级也必须被克隆,并且,如果出现所示情况*,则父级也必须被克隆。
* Root 在 Element1 中被显式设置为父级,因此系统可以识别这种情况并对其进行处理。
问题是,从 Element1、Root 启动克隆
操作也必须被克隆。 Root 的克隆过程规定必须克隆所有子元素,因此再次调用 Element1 的克隆操作,然后重复相同的克隆过程,产生无限循环。
此外,根不会包含 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;
}
I have an object-oriented parent-child tree in PHP that I want to clone.
The difficult part is that the access to the tree is not always through the root, but sometimes through a child of the root, like this:
[Root]
-- [Element1] START CLONE
-- [Element3]
-- [Element4]
-- [Element2]
-- [Element5]
So what I want to do is to clone the entire tree, by calling $new = clone $element1;
The __clone() method states that each of the children must also be cloned, and, if the illustrated situation occurs*, also the parent must be cloned.
* Root is explicitly set as parent in Element1, so the system can identify this situation and do something with it.
The problem is that, starting the clone
operation from Element1, Root must also be cloned. The cloning procedure for Root prescribes that all child elements must be cloned and therefore the clone
operation for Element1 is called again, which then repeats the same cloning procedure, producing an endless loop.
Furthermore, the Root will not contain the first clone of Element1, but it will produce its own clone to add as a child. Element1 will then have Root as its parent, but Root will not have the same Element1 as a child.
I hope I presented the problem in a clear way and that someone can help me find a solution.
EDIT:
Final solution:
/**
* 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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
首先,简化你的例子:
然后你所做的事情有所不同,我认为你有三个操作
类之外的代码正在使用公共克隆方法。但是
__clone()
方法一定不能使用该方法,否则您会遇到您所描述的循环问题。因此__clone()
实现必须使用其他方法。将
cloneSelf
和cloneSingle
方法添加到您的类中,使它们受到保护,以便继承的类可以调用它们,但它们不公开可用。然后在 __clone() 实现中使用它们:
这些方法还将帮助您在没有父级的情况下进行克隆。
First of all, simplify your example:
Then differ between what you do, I think you have got three operations
Code outside of your classes is using the public clone method. But the
__clone()
method must not use that method, otherwise you run into the circular looping problem you've described. So the__clone()
implementation must use other methods.Add a
cloneSelf
andcloneSingle
method to your class, make them protected, so inherited classes can call them but they are not publicly available.Then make use of them in the
__clone()
implementation:These methods will also help you to clone in case there is no parent.
如果向 __clone() 方法添加参数会怎样? - 让我们称之为
$called_from
根据该参数的值,您知道该怎么做:
child
时克隆是从外部调用的,因此您将在父节点上调用__clone()
,并__clone()
时 发送“child”作为值“孩子”或'external' 值设置为$called_from
,它通过调用__clone()
并将$called_from
设置为 'parent' 来启动真正的克隆过程< strong>编辑
我不知道内置的
clone
关键字。因此,您可以创建一个所有树对象都继承自的基类 - 该类可以有一个静态变量,该变量将指示当设置为 true 时克隆必须执行的操作>clone
算法会被执行,否则,__clone()
父对象false
,并且只有根节点将其设置为true,就在它开始克隆子级之前这个基类也可以覆盖__clone() 方法,在单个位置实现该算法。
What if you add a parameter tot the
__clone()
method? - let's call it$called_from
Based on the value of that parameter you know what to do:
child
then clone was called from an external place, so you will call__clone()
on parent with, sending 'child' as value__clone()
is finally called on root node with 'child' or 'external' value set to$called_from
, it starts the real cloning process by calling__clone()
with$called_from
set to 'parent'Edit
I was not aware of the builtin
clone
keyword. So, you could create a base class that all your tree objects are inheriting from - this class could have astatic
, variable that will indicate what clone has to act likeclone
algorithm will be executed, otherwise, will__clone()
the parent objectfalse
, and only the root node sets this to true, just before it starts cloning the childrenThis base class can also override the __clone() method, to implement this algorithm in a single place.