2012-02-19 83 views
3

我试图json_encodedebug_backtrace输出用于将此信息存储在数据库中。如何删除递归?

问题是有时它包含递归。我不在乎的东西。在检测到递归的地方只需要*RECURSION*就足够了。

我该怎么做?

+2

数据库值不需要编码为JSON。 – alex

+0

使用序列化:) – Vyktor

+0

嗯,我需要存储这些数据作为错误报告的一部分。我不关心关系,或者我应该说,我不想为追溯信息创建额外的2个表。 – Gajus

回答

0

序列化确实是一个很好的选择。

由于缺乏这一点,所以没有其他方法来遍历树,保留所有数组和对象,看看它们是否引用相同的值。

由于可以使用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); 

?> 
+0

我不认为它与循环函数有关。 debug_backtrace的输出仍然可以通过'object'和'args'键包含循环引用。 – Evert

1

我也有类似的问题我自己。我也用一个经过并删除了所有递归引用的函数来解决它。讽刺的是,这样做的功能本身就是递归的!这是我想出了:

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

纠正我,如果我错了,但它看起来像堆栈参数不应该通过引用传递在这里,因为它修改堆栈的所有层递归,而不是只有一个下层。 –

+0

这是不正确的。您正在执行深度优先搜索,这会产生错误的输出 – Benubird