【问题标题】:How to check for circular references in PHP when recursively parsing an associative array?递归解析关联数组时如何检查PHP中的循环引用?
【发布时间】:2014-07-15 20:32:15
【问题描述】:

我用循环引用创建了这个数组:

$arr = array(1 => 'one', 2 => 'two');
$arr[3] = &$arr;

我有一个函数可以递归地打印出数组中的值,但我确实无法解决创建循环引用检查的问题。你怎么能这样做?

我用于打印数组的当前函数复制如下。我没有包括我在进行循环引用检查时所做的各种尝试。他们主要围绕维护一个$seen 数组的策略,该数组已经为每个递归分支打印了。这是因为我仍然希望允许打印重复值,如果它是正在解析的当前数组的父级,则不打印值。

我遇到的问题是弄清楚如何向这个$seen 变量添加引用而不是数组副本。但如果可行的话,我很乐意同时使用另一种策略。

function HTMLStringify($arr)
{

    if(is_array($arr)){
        $html = '<ul>';
        foreach ($arr as $key => $value) {

            $html .= '<li>' . $key;

            if(is_array($value)){

                //Conspicuously missing is a circular reference check,
                //causing infinite recursion. After a few failed attempts
                //at checking for this (e.g. discovering that array_push doesn't take references)
                //I have left it for further study.
                //(After all, Javascript's JSON.stringify() doesn't check for circular references)
                //TODO: Check for circular references

                $html .= HTMLStringify($value, $seen);
            }
            elseif(is_numeric($value) || is_string($value) || is_null($value))
            {
                $html .= ' = ' . $value;
            }
            else
            {
                $html .= ' [couldn\'t parse ' . gettype($value) . ']';
            }

            $html .= '</li>';

        }
        $html .= '</ul>';
        return $html;
    }
    else
    {
        return null;
    }
}

【问题讨论】:

标签: php arrays recursion circular-reference


【解决方案1】:

使用来自the answer linked by Ryan Vincent 的严格in_array 检查的代码的改编版本如下所示:

function HTMLStringify($arr, array $seen = array()) {
    if (is_array($arr)) {
        $seen[] = $arr;
        $html = '<ul>';

        foreach ($arr as $key => $value) {
            $html .= '<li>' . $key;

            if (is_array($value)) {

                if (in_array($value, $seen, true)) {
                    // Deal with recursion in your own way here
                    $html .= ' [RECURSION]';
                } else {
                    $html .= HTMLStringify($value, $seen);
                }

            } elseif (is_numeric($value) || is_string($value) || is_null($value)) {
                $html .= ' = ' . $value;
            } else {
                $html .= ' [couldn\'t parse ' . gettype($value) . ']';
            }

            $html .= '</li>'; 
        }

        return $html . '</ul>';
    } else {
        return null;
    }
}

$arr = array(1 => 'one', 2 => 'two');
$arr[3] = &$arr;
echo HTMLStringify($arr);

Comparing across a number of PHP versions,看起来这适用于 PHP 5.3.15+ 和 PHP 5.4.5+。

【讨论】:

    【解决方案2】:

    我正在使用此功能进行调试。还升级为检测递归链接。

    function print_table($mixed, $level=9, $_callstack=array()){
      if($level<=0){ echo '**LIMIT**'; return; }  
    
      if( array_search(serialize($mixed), $_callstack)!==false){
          echo '***recursive detected***';
          return ;
      }    
      $_callstack[] = serialize($mixed);
    
      if(is_array($mixed)){
        echo '<table cellspacing="0" width="100%" border="1">';
        foreach($mixed as $key=>$val){
          echo '<tr><td width="20%">'.$key.'</td><td>';
          if(is_array($val)){
            print_table($val,$level-1, $_callstack);
          }elseif(is_null($val)){
            echo '<span style="color:blue">null</span>';
          }elseif($val===false){
            echo '<span style="color:red">false</span>';
          }elseif($val===true){
            echo '<span style="color:green">true</span>';
          }elseif(is_numeric($val) && $val>1000000000){
            echo $val,' <span style="color:gray">[',date('d-m-Y H:i:s',$val),']</span>';
          }elseif($val===''){
            echo '<span style="color:blue">empty string</span>';      
          }else{
            echo $val;
          }
          echo '</td></tr>';
        }
        echo '</table>';
      }else{
        var_dump($mixed);
      }
    }
    

    如您所见,我收集序列化对象,然后进行比较。需要序列化,因为简单地比较递归对象会引发致命错误:

    $arr=array(&$arr);
    $arr==$arr; // Fatal error: Nesting level too deep - recursive dependency? 
    // php 5.2.9
    

    但是序列化支持递归对象!所以,我们应该比较序列化的字符串,但是序列化会占用大量的时间和内存。 如果你能找到另一种方法 - 请告诉我:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-05
      • 2014-02-26
      • 1970-01-01
      相关资源
      最近更新 更多