views:

67

answers:

1

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)

+6  A: 

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.

rojoca
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.
Gordon
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()`...
TomcatExodus
Gordon
@Gordon - excellent point(s).
rojoca
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).
TomcatExodus
I found this article (http://www.htmlist.com/development/extending-php-5-3-closures-with-serialization-and-reflection/) 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.
TomcatExodus