SO,
I have an issue with determining recursion in arrays in PHP. Assume that I have a dynamic-generated array, which finally can looks like:
$rgData = [
['foo', 'bar', $rgTemp=[7, 31, true]],
[-5, &$rgData, 'baz']
];
(links to variables here are provided dynamically and may refer to an array itself). Another sample:
$rgData = [
['foo', 'bar', $rgTemp=[7, 31, true]],
[-5, &$rgTemp, 'baz']
];
Both arrays have some references inside, but second looks good since it's reference is not cycled. Later, due to my logic, I have to handle array via recursive functions (something like array_walk_recursive
) - and, of cause, I got Fatal error due to infinite nested array recursion in case of first sample above.
My question is - how to determine if an array has infinite recursion. Note, that this question is more complicated than simple search link from inside array to itself, because we can have something like:
$rgOne = [
['foo', 'bar'],
['baz']
];
$rgTwo = [6, 'test', &$rgOne];
$rgOne[1][] = &$rgTwo;
i.e. more complicated recursion. I found that PHP can resolve this somehow in var_dump
and similar functions - for example, dump of the third sample will look like:
array(2) { [0]=> array(2) { [0]=> string(3) "foo" [1]=> string(3) "bar" } [1]=> array(2) { [0]=> string(3) "baz" [1]=> &array(3) { [0]=> int(6) [1]=> string(4) "test" [2]=> &array(2) { [0]=> array(2) { [0]=> string(3) "foo" [1]=> string(3) "bar" } [1]=> *RECURSION* } } } }
i.e. *RECURSION* was caught. Currently, I've tried to resolve a matter via function:
function isLooped(&$rgData, &$rgCurrent=null)
{
foreach($rgData as $mKey=>$mValue)
{
if(is_array($mValue) && isset($rgCurrent) &&
$rgCurrent===$rgData /* that's where, it seems, I need help*/)
{
return true;
}
elseif(is_array($mValue) && isLooped($mValue, $rgData))
{
return true;
}
}
return false;
}
but with no success (and I know why - that comparison is invalid). The only idea I have now is to do weird thing, like:
function isLooped(&$rgData)
{
$rgTemp = @var_export($rgData, 1);
return preg_match('/circular references/i', error_get_last()['message']);
}
but that is sad since I need at least copy my array data to some temporary storage (and, besides, all of this looks like a glitch, not a proper solution). So, may be there are some ideas of how to do that normal way?
Update: I've found a solution via changing key in the array and then looking for it in recursive loop. This is much better than var_*
functions, but still not exactly what I want. Is there a way to do this without var_*
functions or changing original array?
1 Answer 1
The problem is that PHP doesn't have a mechanism to tell you whether two variables reference the same zval (internal data type representing the actual held data). This rules out keeping track of the variables you have traversed so far as a solution.
Without this feature or modifying elements (pin method) it's unfortunately not possible to detect a recursive data structure except for var_dump()
or print_r()
hacks.
-
So, it seems, that the answer I'm looking for (i.e. "No, this can't be done with such conditions"). Thanks.Alma Do– Alma Do08/26/2013 11:11:26Commented Aug 26, 2013 at 11:11
-
Suddenly :p Only one my question on SO was resolved positive :p (and solution to it I've implemented myself)Alma Do– Alma Do08/26/2013 11:57:43Commented Aug 26, 2013 at 11:57
print_r
/var_dump
e.t.c - functions. Another solution there is to change array itself (and check again then) - this looks better but still not enough to answer: is it possible to do normal way or not (negative answer is also good for me - I'll know that it's simpler to change architecture itself). Thanks!