When you create a method that returns a closure in PHP:
class ExampleClass {
public function test() {
$example = 10;
return function() use ($example) {
return $example;
};
}
}
The result of print_r
contains this
(the class whose method created the closure) and static
, which appears to be the values bound within the use ()
statement of the closure:
$instance = new ExampleClass();
$closure = $instance->test();
print_r($closure);
Producing:
Closure Object (
[static] => Array (
[example] => 10
)
[this] => ExampleClass Object()
)
However I cannot for the life of me work out how to capture these values. It is not possible to use any form of property accessor (e.g. $closure->static
or $closure->{'static'}
) without receiving the following:
PHP Fatal error: Uncaught Error: Closure object cannot have properties in XYZ.
Array access notation obviously does not work either:
PHP Fatal error: Uncaught Error: Cannot use object of type Closure as array in XYZ.
JSON encoding the object, besides this making the values useless were they objects, provides an empty JSON object {}
and using the ReflectionFunction
class does not provide access to these items.
The closure documentation does not provide any means of accessing these values at all either.
Outside of doing something shameful like output buffering and parsing print_r
or similar, I cannot actually see a way to get these values.
Am I missing something obvious?
Note: The use-case is for implementing memoization and these values would be extremely beneficial in identifying whether or not the call matched a previous cached call.
A closure is an anonymous function that can access variables imported from the outside scope without using any global variables. Theoretically, a closure is a function with some arguments closed (e.g. fixed) by the environment when it is defined. Closures can work around variable scope restrictions in a clean way.
A closure is a separate namespace, normally, you can not access variables defined outside of this namespace. There comes the use keyword: use allows you to access (use) the succeeding variables inside the closure. use is early binding. That means the variable values are COPIED upon DEFINING the closure.
Basically a closure in PHP is a function that can be created without a specified name - an anonymous function. Here's a closure function created as the second parameter of array_walk() . By specifying the $v parameter as a reference one can modify each value in the original array through the closure function.
The Closure class ¶Class used to represent anonymous functions. Anonymous functions yield objects of this type. This class has methods that allow further control of the anonymous function after it has been created. Besides the methods listed here, this class also has an __invoke method.
It seems you may have overlooked some of the ReflectionFunction
methods.
Take a look at the ReflectionFunction::getClosureThis()
method. I tracked it down by looking through the PHP 7 source code by doing a search for the zend_get_closure_this_ptr()
which is defined in zend_closures.c
.
The manual currently doesn't have a lot of documentation for this function. I'm using 7.0.9; try running this code based on your example:
class ExampleClass {
private $testProperty = 33;
public function test() {
$example = 10;
return function() use ($example) {
return $example;
};
}
}
$instance = new ExampleClass();
$closure = $instance->test();
print_r($closure);
$func = new ReflectionFunction($closure);
print_r($func->getClosureThis());
You should get output similar to
Closure Object
(
[static] => Array
(
[example] => 10
)
[this] => ExampleClass Object
(
[testProperty:ExampleClass:private] => 33
)
)
ExampleClass Object
(
[testProperty:ExampleClass:private] => 33
)
Regarding the closure static variables, these are returned with ReflectionFunction::getStaticVariables()
:
php > var_dump($func->getStaticVariables());
array(1) {
["example"]=>
int(10)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With