0

I'm trying to find a way to get a string representation of a variable in PHP for checking if I've encountered that variable before. I'm implementing a function that recursively processes an array and it would be useful to prevent infinite recursion.

Right now I'm storing a reference to each variable I've processed in a separate array and then comparing that to the current variable (using === to see if they are the same instance), but that requires an O(n) lookup. If I can get a consistent string representation I can change that to an O(1) operation.

I was hoping I could get the internal variable ID or something similar.

Here is an example of what I'm doing now (super basic):

$a = ['a' => 'value a', 'b' => 'value b'];
$b = ['test' => &$a];
$c = ['a' => &$a, 'b' => &$b];
$a['c'] = &$c;
$b['c'] = &$c;

function process_array($array, &$tracker, $depth = 0)
{
    foreach ($array as $key => $value) {
        if (is_array($value)) {
            // Check for recursion
            foreach ($tracker as $prev) {
                if ($prev === $value) {
                    echo str_repeat(' ', $depth * 2) . "*RECURSION*\n";
                    return;
                }
            }

            // Keep track of variables we have already processed to detect recursion
            $tracker[] = &$value;

            echo str_repeat(' ', $depth * 2) . "Key: {$key}\n";
            process_array($value, $tracker, $depth + 1);
        } else {
            echo str_repeat(' ', $depth * 2) . "Key: {$key}\n";
            echo str_repeat(' ', $depth * 2) . "Value: {$value}\n";
        }
    }
}

$tracker = array();
process_array($c, $tracker);

Output:

Key: a
  Key: a
  Value: value a
  Key: b
  Value: value b
  Key: c
    *RECURSION*
*RECURSION*

And another example, I'm trying to achieve something similar to print_r:

Array
(
    [a] => Array
        (
            [a] => value a
            [b] => value b
            [c] => Array
                (
                    [a] => Array
 *RECURSION*
                    [b] => Array
                        (
                            [test] => Array
 *RECURSION*
                            [c] => Array
 *RECURSION*
                        )

                )

        )

    [b] => Array
        (
            [test] => Array
                (
                    [a] => value a
                    [b] => value b
                    [c] => Array
                        (
                            [a] => Array
 *RECURSION*
                            [b] => Array
 *RECURSION*
                        )

                )

            [c] => Array
                (
                    [a] => Array
                        (
                            [a] => value a
                            [b] => value b
                            [c] => Array
 *RECURSION*
                        )

                    [b] => Array
 *RECURSION*
                )

        )

)
Brandon
  • 16,382
  • 12
  • 55
  • 88
  • What kind of variable are we talking about? `===` will happily tell you that two unrelated integer zeroes are "the same instance". – Jon Jan 24 '15 at 01:03
  • Objects and arrays primarily. Like I said, I'm trying to avoid infinite recursion (I process every key => value pair in an array, and if the value is an array or object I call the function on that, which repeats) – Brandon Jan 24 '15 at 01:04
  • 2
    i think some example code of what your currently doing would help –  Jan 24 '15 at 01:05
  • 1
    Agree with Dagon. You might find [`spl_object_hash`](http://php.net/manual/en/function.spl-object-hash.php) useful, but I still can't quite make sense of the question. – Jon Jan 24 '15 at 01:09
  • Example added, but I felt the question was pretty clear to begin with. spl_object_hash looks promising, but it only works on objects, not arrays – Brandon Jan 24 '15 at 01:11
  • 2
    @BrandonWamboldt if your goal is to detect recursion: I have already answered [another question](http://stackoverflow.com/q/14751708/50079) showing how to do it. There is absolutely no way in PHP to tell if two identical arrays are the same instance, but you can detect recursion if you don't mind getting your hands really dirty. – Jon Jan 24 '15 at 01:16
  • Take a look at this : http://stackoverflow.com/questions/7799446/unique-id-of-variable-like-spl-object-hash – Whirlwind Jan 24 '15 at 01:17
  • @Whirlwind That won't detect real recursion unfortunately. If there is no way to do what I'm attempting I'll stick with my O(n) version, but I was hoping I could access the zval ID or something like that – Brandon Jan 24 '15 at 01:18
  • I know, that's why I provided you with this link. It seems infeasible. If you came up with something, let us know. – Whirlwind Jan 24 '15 at 01:21
  • Something useful for debugging zvals http://php.net/manual/en/function.debug-zval-dump.php – Whirlwind Jan 24 '15 at 01:50
  • Yeah my actual code is a bit more sophisticated but also rather complex. I definitely didn't catch the false positive in my example though, thanks for the heads up. – Brandon Jan 24 '15 at 03:26

0 Answers0