обнаружение бесконечной рекурсии массива в PHP?

Я только что переработал свой алгоритм обнаружения рекурсии в моем проекте-проекте dump_r ()

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

обнаружение рекурсии объекта не слишком сложно – вы используете spl_object_hash (), чтобы получить уникальный внутренний идентификатор экземпляра объекта, сохранить его в dict и сравнить с ним при сбрасывании других узлов.

для обнаружения рекурсии массива, я немного озадачен, я не нашел ничего полезного. Сам php способен идентифицировать рекурсию, хотя кажется, что это слишком поздно. EDIT: nvm, это происходит там, где это необходимо 🙂

$arr = array(); $arr[] = array(&$arr); print_r($arr); 

нужно ли прибегать к отслеживанию всего в стеке рекурсии и делать мелкие сравнения с каждым другим элементом массива?

любая помощь будет оценена,
благодаря!

Solutions Collecting From Web of "обнаружение бесконечной рекурсии массива в PHP?"

Из-за механизма вызова по значению PHP единственное решение, которое я вижу здесь, это перебрать массив по ссылке и установить в нем произвольное значение, которое вы позже проверите, существует ли оно, чтобы узнать, были ли вы там раньше:

 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']); } с 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']); } 

Вы можете перенести эту функцию в другую функцию, которая принимает значения вместо ссылок, но затем вы получите уведомление RECURSION со второго уровня. Я думаю, что print_r тоже делает то же самое.

Кто-то исправит меня, если я ошибаюсь, но PHP на самом деле обнаруживает рекурсию в нужный момент. Ваше назначение просто создает дополнительный цикл. Примером может служить:

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

Это приведет к

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

Как и ожидалось.


Ну, мне стало немного любопытно, как обнаружить рекурсию, и я начал работать с Google. Я нашел эту статью http://noteslog.com/post/detecting-recursive-dependencies-in-php-composite-values/ и это решение:

 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; }