Как убрать рекурсию? - PullRequest
       23

Как убрать рекурсию?

3 голосов
/ 19 февраля 2012

Я пытаюсь json_encode debug_backtrace выводить с целью сохранения этой информации в базе данных.

Проблема в том, что иногда она содержит рекурсию.Что-то, что меня не волнует.Достаточно просто *RECURSION* в точке, где обнаружена рекурсия.

Как мне это сделать?

Ответы [ 2 ]

1 голос
/ 04 августа 2012

У меня была похожая проблема.Я тоже разрешил это с помощью функции, которая прошла через все рекурсивные ссылки и удалила их.Иронично, что функция для этого сама по себе рекурсивна!Вот что я придумал:

public static function remove_recursion(&$object, &$stack = array()) {
    if ((is_object($object) || is_array($object)) && $object) {
        if (!in_array($object, $stack, true)) {
            $stack[] = $object;
            foreach ($object as &$subobject) {
                self::remove_recursion($subobject, $stack);
            }
        } else {
            $object = "***RECURSION***";
        }
    }
    return $object;
}

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

0 голосов
/ 19 февраля 2012

serialize действительно была бы хорошей альтернативой.

Без этого нет другого пути, кроме как пройти по дереву, сохранить все массивы и объекты и посмотреть, ссылаются ли они на одно и то же значение.

Для объектов это немного проще, потому что вы можете использовать spl_object_hash.

Для массивов я могу думать только сейчас о следующем:

function referToTheSame(&$arr1, &$arr2) {
  // copy
  $tmp = $arr1;

  $arr1 = 'foo';
  $result = ($arr2==='foo');
  $arr1 = $tmp;

  return $result;

}

Хотелось бы услышать, если есть более умный способ.

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

РЕДАКТИРОВАТЬ

Не мог с собой поделать.Это нарушает ссылки на массивы, но не ссылки на объекты.Конечно, вы можете понять это:

(предупреждение: некрасивый код)

<?php

$structure = array(
    0 => 'foo',
    1 => 'bar',
);

$structure[] =& $structure;

function traverse($item, &$stack) {

    foreach($item as $key=>&$value) {

        if (is_array($value)) {

            // Checking if this array already appeared in the stack
            foreach($stack as &$array2) {

                // Copy
                $tmp = $array2;
                $array2 = 'foo';
                if ($value==='foo') {
                    $array2 = $tmp;

                    // We need to create another temporary value, to break the 
                    // reference.
                    $newValue = '* INCEPTION *';
                    $value =& $newValue;
                    continue 2; 
                } else {
                    $array2 = $tmp;
                }

            }

            $stack[] =& $value;
            traverse($value, $stack);
            array_pop($stack);

        }

    }

}

$stack = array();
$stack =& $structure;
traverse($structure, $stack);

print_r($structure);

?>
...