10

Is there a way that one can implicitly declare top-level variables as global for use in closures?

For example, if working with code such as this:

$a = 0; //A TOP-LEVEL VARIABLE

Alpha::create('myAlpha')
    ->bind(DataSingleton::getInstance()
        ->query('c')
    )
    ->addBeta('myBeta', function($obj){
        $obj->bind(DataSingleton::getInstance()
                ->query('d')
            )
            ->addGamma('myGamma', function($obj){
                $obj->bind(DataSingleton::getInstance()
                        ->query('a')
                    )
                    ->addDelta('myDelta', function($obj){
                        $obj->bind(DataSingleton::getInstance()
                            ->query('b')
                        );
                    });
            })
            ->addGamma('myGamma', function($obj){

                $a++; //OUT OF MY SCOPE

                $obj->bind(DataSingleton::getInstance()
                        ->query('c')
                    )
                    .
                    .
                    .

The closures are called from a method as such:

    public function __construct($name, $closure = null){
        $this->_name = $name;
        is_callable($closure) ? $closure($this) : null;
    }

So in summary/TL;DR, is there a way to implicitly declare variables as global for use in closures (or other functions I suppose) without making use of the global keyword or $GLOBALS super-global?

I started this topic at another forum I frequent (http://www.vbforums.com/showthread.php?p=3905718#post3905718)

1 Answer 1

34

You have to declare them in the closure definition:

->addBeta('myBeta', function($obj) use ($a) { // ...

Otherwise you must use the global keyword. You have to do this for every closure that uses $a too.

Sign up to request clarification or add additional context in comments.

5 Comments

Note that use inherits variables from the parent scope only. In a scenario where the closures are not defined in the global scope, you'd still have to use the global keyword instead. It should work for the OP's scenario though.
Hmm, I was afraid it would be use. Hopefully this issue will not be prevalent in the system I'm developing, as most global calls will be likely made to static instances. I'm trying to fiddle with a trick involving extract() on $GLOBALS and call_user_func_array()...
Also, $a++ like shown in the OP's example would not be applied back to the global $a unless it is used by reference, e.g, &$a. Objects are used by reference though.
Thankyou both rojoca and Gordon. I'm aware of the approach suggested, using use with referenced variables. I was unaware that use only inherits from parent scope, that is good information. Are there any other alternatives? Calling extract($GLOBALS); at the beginning of each closure works, but I'm certain that's far too much overhead being generated. I'd like to keep the in order for this to work, you must [insert-hoop-to-jump-through] to a minimum. Keeping in mind that the closures are always called from the same method(s).
I found this article (htmlist.com/development/…) providing a workaround to extending the final Closure class. By calling extract($GLOBALS); prior to eval() on the function string, this would work. I can see performance suffering terribly using this strategy though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.