Рекурсия родительского/дочернего объекта PHP

У меня взаимоотношения родитель-потомок OO. Родительские объекты имеют много дочерних объектов, и каждый дочерний объект знает о своем родителе по ссылке.

Родительский элемент также может быть дочерним (по сути, это дерево).

Когда я выполняю var_dump() для корневого объекта, он много раз говорит ["parent"]=>RECURSION, и сгенерированное описание будет очень долго.

Мне интересно, если я делаю что-то не так. Если да, меня интересует «лучшая практика».

Спасибо за помощь!


person Damien    schedule 07.01.2011    source источник
comment
некоторый код был бы хорош!   -  person Rene Terstegen    schedule 07.01.2011
comment
Похоже, что у вас есть цикл в вашем графе (родитель, который также является дочерним элементом одного из его потомков), но, не видя кода или примеров данных, трудно сказать наверняка.   -  person FrustratedWithFormsDesigner    schedule 07.01.2011
comment
пока вы уверены, что рекурсия не слишком глубокая, все в порядке. В противном случае вы можете столкнуться с проблемами, например. кодирование объекта с помощью json.   -  person usoban    schedule 07.01.2011
comment
классический случай google.com/search?q=RECURSION (это просто заманчиво)   -  person Hannes    schedule 07.01.2011
comment
Да, я знаю, что такое рекурсия, мой вопрос был о том, является ли это проблемой в PHP (и если это так, то как с ней справиться) или это только портит ответ var_dump.   -  person Damien    schedule 07.01.2011


Ответы (3)


Вы не делаете ничего плохого; у вас есть родитель, который имеет ссылку на своих дочерних элементов, и каждый дочерний элемент имеет обратную ссылку на своего родителя. Когда вы var_dump() выполняете корневой объект, он выполняет итерацию по дочерним объектам, чтобы напечатать их, и, поскольку каждый дочерний объект имеет ссылку на родителя, он возвращается обратно. Поскольку обычно это вызывает бесконечный цикл (родительский -> дочерний -> родительский -> дочерний ->...), PHP хранит список объектов, которые он уже посетил, и когда он встречает такой, он не пытается сбросить это снова, но вместо этого печатает «RECURSION».

Единственное, на что следует обратить внимание, это то, что PHP использует подсчет ссылок для сборки мусора, а циклические конструкции, подобные этим, не разрешаются сами по себе. В результате в вашем скрипте произойдет утечка памяти, что может быть проблемой, а может и не быть. Чтобы решить эту проблему, вам нужно выполнить очистку вручную: непосредственно перед тем, как родительский объект выйдет из области видимости, вам нужно установить все родительские указатели в нуль.

См. также: http://bugs.php.net/bug.php?id=33595.

person tdammers    schedule 07.01.2011
comment
утечка памяти, по-видимому, исправлена ​​в PHP 5.3: (см. последние 2 комментария по адресу: ошибки. php.net/bug.php?id=33595 ) - person Tom Auger; 03.01.2014

Функция var_dump рекурсивно проходит по вашему графу объектов и печатает все доступные данные ваших объектов. Теперь попробуйте перевести приведенную ниже диаграмму на простой английский язык.

        has                var_dump:
Parent ----> Child         "The Parent object has a child object"
^              |               "That Child object has a Parent Object"
|______________| has               "That Parent object …"

Если бы PHP не был достаточно умен, чтобы обнаружить эту рекурсию, он работал бы бесконечно. Поэтому вместо этого он распознает, что этот объект был сброшен ранее, и сбрасывает RECURSION. Вы не делаете ничего плохого.

Нажмите здесь для другого объяснения

person Gordon    schedule 07.01.2011

Единственный способ избежать рекурсивных ссылок — построить «перевернутое дерево», которое полезно только в том случае, если вы хотите выполнять поиск от дочернего к родительскому, не зная братьев и сестер. Нравиться:

class Foo {
    protected $parent;

    public function __construct(Foo $parent = null) {
        $this->parent = $parent;
    }

    public function getParent() {
        return $this->parent;
    }
}

$a = new Foo;
$b = new Foo($a);
$c = new Foo($b);

Таким образом, от $c вы можете отслеживать до корневого узла, являющегося $a, без рекурсивных ссылок.

Если вам нужно перейти от корневого узла к дочерним, то нет другого решения, кроме того, что вы уже сделали, что правильно.

person netcoder    schedule 07.01.2011