[php-src] Issue #8202: Getting the scoped variables and their values from a closure using reflection

From: Date: Tue, 15 Mar 2022 19:03:11 +0000
Subject: [php-src] Issue #8202: Getting the scoped variables and their values from a closure using reflection
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-240347@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/8202 Author: Wuffz ### Description I was trying something to parse closures as statements. Here is a small example using existing functions of what i am actually trying to do ```php <?php $max= 12; $refclass = new \ReflectionClass( fn($u) => $u->age > $max); $scope= $refclass->getProperties(); // or maybe $refclass->getUsedVariables(); something like that? var_dump($scope); // can we access maxage with the value 12 ? ``` Below is a bigger test as a proof of concept, Note that it is just a proof of concept and it does showcase a use for it ```php <?php class Query { public function __construct( private $context ){} /** irrelevant functions **/ private function getChunkOfCode($start, $stop) { $lines = file(__FILE__); $buff = []; for ( $i = $start-1; $i < $stop-1; $i ++ ) { $buff[] = trim($lines[$i],"\r\n"); } return implode("\n", $buff); } /** end of irrelevant functions */ public function where(Closure $l) { // below is a simple example. // in a real world scenario i would probably use a // simple AST to parse the actual expressions and validate them or fallback to actual filterable callbacks. // get as reflection function. $ref = new \ReflectionFunction($l); // get the function body of the closure $output = $this->getChunkOfCode( $ref->getStartLine(), $ref->getEndLine() ); // this should be smarter. but for demo purposes clean it up a bit. $output = explode ( "=>", $output ); $output = trim($output[1]); // use reflection class to parse into any syntax, in this demo its an sql 'where' statement $refcontext = new \ReflectionClass($this->context); // parse to some sql format for demo purposes foreach ( $ref->getParameters() as $param ) { foreach ( $refcontext->getProperties() as $prop ) { $output = str_replace( '$'.$param->getName().'->'.$prop->getName(), ''.$this->context::$EntityName.'.'.$prop->getName().'', $output ); } } // this is where i would try to parse the scoped vars into the output. var_dump($output); } } class UserEntity{ public static $EntityName = 'user_entity'; public function __construct( public $name ){ } } $q = new Query(UserEntity::class); // this will work as the scope is not used. $q->where( fn($c) => $c->name == 12 ); // this will not work, as the scope cannot be accessed $q->where( fn($c) => $c->name == $otherage ); ``` I am willing to help out here, if needed let me know how.

« previous php.bugs (#240347) next »