note 105901 modified in functions.anonymous by danbrown

From: Date: Mon, 26 Sep 2011 14:59:33 +0000
Subject: note 105901 modified in functions.anonymous by danbrown
References: 1  Groups: php.notes 
Request: Send a blank email to php-notes+get-183450@lists.php.net to get a copy of this message
When invoking an anonymous function through throughThroughFunction(), all variables are automatically binded to the inner function. In addition, variables created within the anonymous function are also "binded out" incorporating it to the scope where the anonymous function is being created. Enjoy! <?php class ThroughThrogh { public $to_export = array(); public $to_import = array(); // we eval() these functions in order to cleanup verbosity. Cleaner this way even though we all heard about the nightmares of eval() const TX_START_X = 'foreach(get_defined_vars() as $k=>$v){$this->to_export[$k] =&${$k};};'; const TX_START_I = 'foreach($that->to_export as $name => &$variable) ${$name} = &$variable;'; const TX_END_X = 'foreach(get_defined_vars() as $k=>$v){if(!isset($that->to_export[$k])) $that->to_import[$k] =&${$k};};'; const TX_END_I = 'foreach($this->to_import as $name => &$variable) ${$name} = &$variable;'; public function hackClosure($closure, $inject_start, $inject_end) { $reflection = new ReflectionFunction($closure); $tmp = $reflection->getParameters(); $args = array('$that'); foreach ($tmp as $a) array_push($args, '$' . $a->getName() . ($a->isDefaultValueAvailable() ? '=\'' . $a->getDefaultValue() . '\'' : '')); $file = new SplFileObject($reflection->getFileName()); $file->seek($reflection->getStartLine() - 1); $code = ''; while ($file->key() < $reflection->getEndLine()) { $code .= $file->current(); $file->next(); } $start = strpos($code, '{') + 1; $end = strrpos($code, '}'); return create_function(implode(', ', $args), "$inject_start;" . substr($code, $start, $end - $start) . "$inject_end;"); } //here is where we invoke the function public function throughThroughFunction($that, $callback){ $this->to_export["that"] = $that; $inject_start = self::TX_START_I;// potentially you can add setup code in here $inject_end = self::TX_END_X;// potentially you can add cleanup code in here $callback = $this->hackClosure($callback, $inject_start, $inject_end); call_user_func($callback, $that); } //user test public function test(){ $outscope = "Source External Scope: test... not modified if seen at end of function\n"; $this->test = "Source External Scope: object attribute from outside anonymous function\n"; eval($this::TX_START_X); //required to export all variables from scope $this->throughThroughFunction($this, function(){ echo "Source Anonymous Function\n"; echo $outscope; echo $that->test; $that->test = "Source Anonymous Function Scope: wow! Object attribute modified from inside anonymous function\n"; $outscope = "Source Anonymous Function Scope: yey! Variable Modified from the scope of an anonymous function!\n"; $from_anonymous_function = "Source Anonymous Function Scope: No way! How did you do that?\n"; } ); eval($this::TX_END_I); //require to bring newly created variables from anonymous function into current scope echo "\nSource External Scope\n"; echo $from_anonymous_function; echo $outscope; echo $this->test; } } $demo = new ThroughThrogh(); $demo->test(); ?> Output Source Anonymous Function Source External Scope: test... not modified if seen at end of function Source External Scope: object attribute from outside anonymous function Source External Scope Source Anonymous Function Scope: No way! How did you do that? Source Anonymous Function Scope: yey! Variable Modified from the scope of an anonymous function! Source Anonymous Function Scope: wow! Object attribute modified from inside anonymous function --was-- <?php /* * When invoking an anonymous function through throughThroughFunction(), all variables are automatically binded to the inner function. In addition, variables created within the anonymous function are also "binded out" incorporating it to the scope where the anonymous function is being created. Enjoy! */ class ThroughThrogh { public $to_export = array(); public $to_import = array(); // we eval() these functions in order to cleanup verbosity. Cleaner this way even though we all heard about the nightmares of eval() const TX_START_X = 'foreach(get_defined_vars() as $k=>$v){$this->to_export[$k] =&${$k};};'; const TX_START_I = 'foreach($that->to_export as $name => &$variable) ${$name} = &$variable;'; const TX_END_X = 'foreach(get_defined_vars() as $k=>$v){if(!isset($that->to_export[$k])) $that->to_import[$k] =&${$k};};'; const TX_END_I = 'foreach($this->to_import as $name => &$variable) ${$name} = &$variable;'; public function hackClosure($closure, $inject_start, $inject_end) { $reflection = new ReflectionFunction($closure); $tmp = $reflection->getParameters(); $args = array('$that'); foreach ($tmp as $a) array_push($args, '$' . $a->getName() . ($a->isDefaultValueAvailable() ? '=\'' . $a->getDefaultValue() . '\'' : '')); $file = new SplFileObject($reflection->getFileName()); $file->seek($reflection->getStartLine() - 1); $code = ''; while ($file->key() < $reflection->getEndLine()) { $code .= $file->current(); $file->next(); } $start = strpos($code, '{') + 1; $end = strrpos($code, '}'); return create_function(implode(', ', $args), "$inject_start;" . substr($code, $start, $end - $start) . "$inject_end;"); } //here is where we invoke the function public function throughThroughFunction($that, $callback){ $this->to_export["that"] = $that; $inject_start = self::TX_START_I;// potentially you can add setup code in here $inject_end = self::TX_END_X;// potentially you can add cleanup code in here $callback = $this->hackClosure($callback, $inject_start, $inject_end); call_user_func($callback, $that); } //user test public function test(){ $outscope = "Source External Scope: test... not modified if seen at end of function\n"; $this->test = "Source External Scope: object attribute from outside anonymous function\n"; eval($this::TX_START_X); //required to export all variables from scope $this->throughThroughFunction($this, function(){ echo "Source Anonymous Function\n"; echo $outscope; echo $that->test; $that->test = "Source Anonymous Function Scope: wow! Object attribute modified from inside anonymous function\n"; $outscope = "Source Anonymous Function Scope: yey! Variable Modified from the scope of an anonymous function!\n"; $from_anonymous_function = "Source Anonymous Function Scope: No way! How did you do that?\n"; } ); eval($this::TX_END_I); //require to bring newly created variables from anonymous function into current scope echo "\nSource External Scope\n"; echo $from_anonymous_function; echo $outscope; echo $this->test; } } $demo = new ThroughThrogh(); $demo->test(); /* Output Source Anonymous Function Source External Scope: test... not modified if seen at end of function Source External Scope: object attribute from outside anonymous function Source External Scope Source Anonymous Function Scope: No way! How did you do that? Source Anonymous Function Scope: yey! Variable Modified from the scope of an anonymous function! Source Anonymous Function Scope: wow! Object attribute modified from inside anonymous function */ http://php.net/manual/en/functions.anonymous.php

« previous php.notes (#183450) next »