8

I want my function to access an outside variable—from its parent function specifically. However, using the global keyword sets too broad a scope; I need to limit it. How do I get this code to spit out 'Level 2' instead of 'Level 1'? Do I have to make a class?

<?php
$a = "Level 1";

function first() {
    $a = "Level 2";

    function second() {
        global $a;
        echo $a.'<br />';
    }

    second();
}

first();
//outputs 'Level 1'
?>
Wiseguy
  • 20,522
  • 8
  • 65
  • 81
JP Lew
  • 4,121
  • 2
  • 32
  • 45

2 Answers2

33

Just for the sake of example, if I understand what you're trying to do, you could use a closure (PHP 5.3+), as "Closures may also inherit variables from the parent scope" with the use keyword.

$a = "Level 1";

function first() {
    $a = "Level 2";

    $func = function () use ($a) {
        echo $a.'<br />';
    };

    $func();
}

first();
// prints 'Level 2<br />'

Closures are most commonly used for callback functions. This may not be the best scenario to use one, however. As others have suggested, just because you can do something doesn't mean it's the best idea.

Wiseguy
  • 20,522
  • 8
  • 65
  • 81
  • 1
    I also needed to pass data in and out of the callback function so I had to write `use (&$a)` to pass it by reference. (Remembering matches from a preg_replace_callback scenario.) – ygoe Jan 16 '18 at 19:30
14

PHP has no concept of nested functions or scopes and it's terrible practice to nest functions. What happens is that PHP simply encounters a function declaration and creates a normal function second. If you try to call first again, PHP will again encounter a function declaration for second and crash, since the function second is already declared. Therefore, don't declare functions within functions.

As for passing values, either explicitly pass them as function parameters or, as you say, make a class if that makes sense.

deceze
  • 510,633
  • 85
  • 743
  • 889