detecting infinite array recursion in PHP?

前端 未结 2 493
时光取名叫无心
时光取名叫无心 2021-02-07 11:36

i\'ve just reworked my recursion detection algorithm in my pet project dump_r()

https://github.com/leeoniya/dump_r.php

detecting object recursion is not too diff

相关标签:
2条回答
  • 2021-02-07 12:09

    Someone will correct me if I am wrong, but PHP is actually detecting recursion at the right moment. Your assignation simply creates the additional cycle. The example should be:

    $arr    = array();
    $arr    = array(&$arr);
    

    Which will result in

    array(1) { [0]=> &array(1) { [0]=> *RECURSION* } } 
    

    As expected.


    Well, I got a bit curious myself how to detect recursion and I started to Google. I found this article http://noteslog.com/post/detecting-recursive-dependencies-in-php-composite-values/ and this solution:

    function hasRecursiveDependency($value)
    {
        //if PHP detects recursion in a $value, then a printed $value 
        //will contain at least one match for the pattern /\*RECURSION\*/
        $printed = print_r($value, true);
        $recursionMetaUser = preg_match_all('@\*RECURSION\*@', $printed, $matches);
        if ($recursionMetaUser == 0)
        {
            return false;
        }
        //if PHP detects recursion in a $value, then a serialized $value 
        //will contain matches for the pattern /\*RECURSION\*/ never because
        //of metadata of the serialized $value, but only because of user data
        $serialized = serialize($value);
        $recursionUser = preg_match_all('@\*RECURSION\*@', $serialized, $matches);
        //all the matches that are user data instead of metadata of the 
        //printed $value must be ignored
        $result = $recursionMetaUser > $recursionUser;
        return $result;
    }
    
    0 讨论(0)
  • 2021-02-07 12:11

    Because of PHP's call-by-value mechanism, the only solution I see here is to iterate the array by reference, and set an arbitrary value in it, which you later check if it exists to find out if you were there before:

    function iterate_array(&$arr){
    
      if(!is_array($arr)){
        print $arr;
        return;
      }
    
      // if this key is present, it means you already walked this array
      if(isset($arr['__been_here'])){
        print 'RECURSION';
        return;
      }
    
      $arr['__been_here'] = true;
    
      foreach($arr as $key => &$value){
    
        // print your values here, or do your stuff
        if($key !== '__been_here'){
          if(is_array($value)){
            iterate_array($value);
          }
    
          print $value;
        }
      }
    
      // you need to unset it when done because you're working with a reference...
      unset($arr['__been_here']);
    
    }
    

    You could wrap this function into another function that accepts values instead of references, but then you would get the RECURSION notice from the 2nd level on. I think print_r does the same too.

    0 讨论(0)
提交回复
热议问题