Results 1 to 5 of 5

Thread: Global variables in closure scope

  1. #1

    Thread Starter
    Hyperactive Member tomcatexodus's Avatar
    Join Date
    Feb 2001
    Posts
    372

    Global variables in closure scope

    Is there a way to ensure that top-level variables are visible in the scope of a closure, without needing to declare them global in the closure itself?

    For example; if I'm working with code using a syntax such as this:
    PHP Code:
        $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')
                            )
                            .
                            .
                            . 
    Now of course normally one would need to declare it as global or use the $GLOBALS superglobal. The closures are being called from within a method as such:
    PHP Code:
            public function __construct($name$closure null){
                
    $this->_name $name;
                
    is_callable($closure) ? $closure($this) : null;
            } 
    Providing a jQuery-ish syntax. This is all very simplified for use as an example.

    TL;DR: How can I implicitly declare as global the closure scoped variables.
    IWS

  2. #2

    Thread Starter
    Hyperactive Member tomcatexodus's Avatar
    Join Date
    Feb 2001
    Posts
    372

    Re: Global variables in closure scope

    Here's the whole example for shits n' gigs':
    PHP Code:
        abstract class BaseClass{
            
            protected 
    $_name;
            protected 
    $_data = array();
            protected 
    $_children = array();
            protected 
    $_occurance 0;
            
            
    //class specific, just a general example
            
    public static function create($name$closure null){
                return new static(
    $name$closure);
            }
            
            
    //class specific, just a general example
            
    public function __construct($name$closure null){
                
    $this->_name $name;
                
    is_callable($closure) ? $closure($this) : null;
            }
            
            public function 
    addAlpha($name$closure null){
                
    $this->_children[] = new Alpha($name$closure);
                
    //class specific config
                
    return $this;
            }
            
            public function 
    addBeta($name$closure null){
                
    $this->_children[] = new Beta($name$closure);
                
    //class specific config
                
    return $this;
            }
            
            public function 
    addGamma($name$closure null){
                
    $this->_children[] = new Gamma($name$closure);
                
    //class specific config
                
    return $this;
            }
            
            public function 
    addDelta($name$closure null){
                
    $this->_children[] = new Delta($name$closure);
                
    //class specific config
                
    return $this;
            }
            
            public function 
    set($name$value){
                
    $this->_data[$this->_occurance][$name] = $value;
                return 
    $this;
            }
            
            public function 
    get($name){
                return 
    $this->_data[$this->_occurance][$name];
            }
            
            public function 
    newOccurance(){
                
    $this->_occurance++;
                return 
    $this;
            }
            
            public function 
    bind(Array $data){
                foreach(
    $data as $record){
                    
    $this->newOccurance();
                    foreach(
    $record as $name => $value){
                        
    $this->_data[$this->_occurance][$name] = $value;
                    }
                }
                return 
    $this;
            }
            
        }
        
        class 
    Alpha extends BaseClass{
            
            public function 
    render(){
                echo 
    '<pre>';
                echo 
    preg_replace('% \n+ %ix'"\n"print_r($thistrue));
                echo 
    '</pre>';
            }
            
        }
        
        class 
    Beta extends BaseClass{}
        
        class 
    Gamma extends BaseClass{}
        
        class 
    Delta extends BaseClass{}
        
        
    //just an example of some data source class
        
    class DataSingleton{
            
            private static 
    $_instance;
            private 
    $_data = array();
            
            private function 
    __construct(){}
            
            public static function 
    getInstance(){
                return 
    self::$_instance self::$_instance self::$_instance = new self;
            }
            
            public function 
    import(Array $data){
                
    $this->_data $data;
            }
            
            public function 
    query($sortCharacter){
                foreach(
    $this->_data as $record){
                    foreach(
    $record as $name => $value)
                    if(
    preg_match("% ^{$sortCharacter} %ix"$value)){
                        
    $set[] = $record;
                    }
                }
                return 
    $set;
            }
                    
        }
        
        
    ///////////////////////////////////////////////////////////////////////////
        
        
    DataSingleton::getInstance()
            ->
    import(array(
                array(
    'name' => 'Andrew'), array('name' => 'Andrea'), array('name' => 'Amy'),
                array(
    'name' => 'Brandon'), array('name' => 'Betty'), array('name' => 'Bobby'), array('name' => 'Barry'),
                array(
    'name' => 'Cameron'), array('name' => 'Camille'),
                array(
    'name' => 'Daniel'), array('name' => 'Dale'), array('name' => 'Damien')
            ));
        
        
    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){
                        
    $obj->bind(DataSingleton::getInstance()
                                ->
    query('c')
                            )
                            ->
    addDelta('myDelta', function($obj){
                                
    $obj->bind(DataSingleton::getInstance()
                                    ->
    query('d')
                                );
                            });
                    });
            })
            ->
    render(); 
    IWS

  3. #3

    Thread Starter
    Hyperactive Member tomcatexodus's Avatar
    Join Date
    Feb 2001
    Posts
    372

    Re: Global variables in closure scope

    Outputs:
    Code:
    Alpha Object
    (
        [_name:protected] => myAlpha
        [_data:protected] => Array
            (
                [1] => Array
                    (
                        [name] => Cameron
                    )
                [2] => Array
                    (
                        [name] => Camille
                    )
            )
        [_children:protected] => Array
            (
                [0] => Beta Object
                    (
                        [_name:protected] => myBeta
                        [_data:protected] => Array
                            (
                                [1] => Array
                                    (
                                        [name] => Daniel
                                    )
                                [2] => Array
                                    (
                                        [name] => Dale
                                    )
                                [3] => Array
                                    (
                                        [name] => Damien
                                    )
                            )
                        [_children:protected] => Array
                            (
                                [0] => Gamma Object
                                    (
                                        [_name:protected] => myGamma
                                        [_data:protected] => Array
                                            (
                                                [1] => Array
                                                    (
                                                        [name] => Andrew
                                                    )
                                                [2] => Array
                                                    (
                                                        [name] => Andrea
                                                    )
                                                [3] => Array
                                                    (
                                                        [name] => Amy
                                                    )
                                            )
                                        [_children:protected] => Array
                                            (
                                                [0] => Delta Object
                                                    (
                                                        [_name:protected] => myDelta
                                                        [_data:protected] => Array
                                                            (
                                                                [1] => Array
                                                                    (
                                                                        [name] => Brandon
                                                                    )
                                                                [2] => Array
                                                                    (
                                                                        [name] => Betty
                                                                    )
                                                                [3] => Array
                                                                    (
                                                                        [name] => Bobby
                                                                    )
                                                                [4] => Array
                                                                    (
                                                                        [name] => Barry
                                                                    )
                                                            )
                                                        [_children:protected] => Array
                                                            (
                                                            )
                                                        [_occurance:protected] => 4
                                                    )
                                            )
                                        [_occurance:protected] => 3
                                    )
                                [1] => Gamma Object
                                    (
                                        [_name:protected] => myGamma
                                        [_data:protected] => Array
                                            (
                                                [1] => Array
                                                    (
                                                        [name] => Cameron
                                                    )
                                                [2] => Array
                                                    (
                                                        [name] => Camille
                                                    )
                                            )
                                        [_children:protected] => Array
                                            (
                                                [0] => Delta Object
                                                    (
                                                        [_name:protected] => myDelta
                                                        [_data:protected] => Array
                                                            (
                                                                [1] => Array
                                                                    (
                                                                        [name] => Daniel
                                                                    )
                                                                [2] => Array
                                                                    (
                                                                        [name] => Dale
                                                                    )
                                                                [3] => Array
                                                                    (
                                                                        [name] => Damien
                                                                    )
                                                            )
                                                        [_children:protected] => Array
                                                            (
                                                            )
                                                        [_occurance:protected] => 3
                                                    )
                                            )
                                        [_occurance:protected] => 2
                                    )
                            )
                        [_occurance:protected] => 3
                    )
            )
        [_occurance:protected] => 2
    )
    IWS

  4. #4
    PowerPoster
    Join Date
    Sep 2003
    Location
    Edmonton, AB, Canada
    Posts
    2,629

    Re: Global variables in closure scope

    PHP is not like JavaScript. In JavaScript, an anonymous function just automatically inherits the entire scope of its parent. In PHP, you must define, explicitly, the scope variables that it should inherit from its parent. And, you must do this by reference, because otherwise you are just copying that scope's variable.

    The following is what you want:
    PHP Code:
    $obj->method(function() use(&$a){
      
    $a++;
    }); 
    So, to have a nested closure:
    PHP Code:
    $a 0;
    $obj->methodA(function($obj) use(&$a){
      echo 
    $a// prints 0
      
    $obj->methodB(function() use(&$a){
        
    $a++;
      }
    });
    echo 
    $a// prints 1 
    read more about closures in PHP.
    Last edited by kows; Oct 30th, 2010 at 02:09 AM.
    Like Archer? Check out some Sterling Archer quotes.

  5. #5

    Thread Starter
    Hyperactive Member tomcatexodus's Avatar
    Join Date
    Feb 2001
    Posts
    372

    Re: Global variables in closure scope

    Thanks kows;

    I've discovered a few work-a-rounds. Specifically, 'extending' the Closure class (rather, just creating a new class with some Reflection tricks) and calling extract($GLOBALS); prior to an eval(); on the extracted function code. Despite it's functionality, it's hackish. I'm certain that in a production scenario, using the Reflection API tricks in conjunction with the continual re-scoping/extraction of $GLOBALS would be terribly inefficient.

    I posted this up and linked to this thread at another forum. It has a link to the blog entry regarding 'extending' Closure. http://stackoverflow.com/questions/4...variable-scope
    IWS

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width