Chris Morrow
Chris Morrow

Reputation: 63

Function with foreach unexpectedly retaining variable's value

I'm trying to grab and print all paths from root to leaf in a nested PHP array. So for example, if this is my array:

$tree = array(
    "A" => "w",
    "B" => array("x" => array("y", "z"))
)

I want the following as output:

Array
(
    [0] => Aw
    [1] => Bxy
    [2] => Bxz
)

Here's my function at present:

function traverse($input, $myPath) {
    global $allPaths;
    if(is_array($input)) {
        foreach($input as $k => $v) {
            if(!is_int($k)) $myPath .= $k;
            traverse($v, $myPath);
        }
    } else {
        $myPath .= $input;
        $allPaths[] = $myPath;
    }
}

When I run this code:

$allPaths = array();
echo "<pre>";
traverse($tree, "");
print_r($allPaths);
echo "</pre>";

The output is this:

Array
(
    [0] => Aw
    [1] => ABxy
    [2] => ABxz
)

That's almost correct, but for some reason the A is being retained when it reaches the "B" part instead of being reset as I would expect.

I've re- and re-read the code and tried every debugging message I can think of, and still don't get what's going on. I'm sure it's either something basic (perhaps so much so that if I haven't seen it yet, I never will) or I'm just not getting how variable scope is working here.

Upvotes: 1

Views: 39

Answers (1)

Steve
Steve

Reputation: 20469

The 1st call to the function runs over the top level array, so the top level keys always get appended.

To fix, pass a copy of $myPath with $k appened to the recursive calls, rather than appending to $myPath directly:

function traverse($input, $myPath) {
    global $allPaths;
    if(is_array($input)) {
        foreach($input as $k => $v) {
            if(!is_int($k)){
                traverse($v, $myPath . $k);
            }else{
                traverse($v, $myPath);
            }
        }
    } else {
        $myPath .= $input;
        $allPaths[] = $myPath;
    }
}

Upvotes: 1

Related Questions