Monday, 26 August 2013

Determine infinite nested array in PHP

Determine infinite nested array in PHP

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?

No comments:

Post a Comment