У меня есть объектно-ориентированное родительско-дочернее дерево в PHP, которое я хочу клонировать.
Сложность заключается в том, что доступ к дереву осуществляется не всегда через корень, а иногда через дочерний элемент корня, например:
[Root]
-- [Element1] START CLONE
-- [Element3]
-- [Element4]
-- [Element2]
-- [Element5]
Итак, я хочу клонировать все дерево, вызвав $new = clone $element1;
Метод __clone () указывает, что каждый из дочерних элементов также должен быть клонирован, и, если проиллюстрирована ситуация *, также должен быть клонирован родительский элемент.
* Root явно установлен как родительский элемент в Element1, поэтому система может идентифицировать эту ситуацию и что-то с ней сделать.
Проблема в том, что, начиная операцию clone
с Элемента1, Root также должен быть клонирован. Процедура клонирования для Root предписывает, что все дочерние элементы должны быть клонированы, и поэтому снова вызывается операция clone
для Element1, которая затем повторяет ту же процедуру клонирования, создавая бесконечный цикл.
Кроме того, Корень не будет содержать первый клон Element1, но он создаст свой собственный клон, который будет добавлен как ребенок. Элемент 1 будет иметь Root в качестве родителя, но Root не будет иметь тот же элемент 1, что и дочерний элемент.
Надеюсь, я ясно изложил проблему и что кто-то может помочь мне найти решение.
EDIT:
Окончательное решение:
/**
* 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;
}