How to check circular references in PHP when recursively parsing an associative array?

I created this array with a circular reference:

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

I have a function that recursively outputs values โ€‹โ€‹in an array, but I really could not solve the problem of creating a circular check. How can you do this?

The current function that I have to print the array is copied below. I did not include the various attempts I made during the round check. They basically revolved around a strategy to support an array of $seenelements that were already printed for each recursion branch. This is because I still want to allow the printing of duplicate values, and not print the value if it is the parent of the current array that is being processed.

I am having problems with how to add links, not copies of arrays to this variable $seen. But I would be happy to use a different strategy together if it worked.

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 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;
    }
}
+4
source share
2 answers

The following is an adapted version of your code using strict verification in_arrayfrom the answer related to Ryan Vincent :

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 with several versions of PHP , it looks like this will work for PHP 5.3.15+ and PHP 5.4.5+.

+1
source

I use this function for debugging. Also updated to detect recursive reference.

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

! , , . - :)

0

Source: https://habr.com/ru/post/1542114/


All Articles