In PHP, you can have named functions like this:
function foo()
{
return "bar";
}
And you can have Closures like this:
$foo = function() {
return "bar";
};
Closures are awesome and easy to create, but unfortunately a library I need to use really wants a named function. Is it possible to create a named function from closures dynamically? I.e. not defining all functions in code ahead of time, but more like a register_function($name, callable $closure)
.
I am aware of create_function
, but that one takes a PHP string as function body and just eval
s it, which is not what I'm looking for.
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function.
Difference between Function and ClosureFunction is declared using func keyword whereas Closure doesn't have func keyword. Function has always name but Closure doesn't have. Function doesn't have in keyword but closure has in the keyword.
Although C was created two decades after Lisp, it nonetheless lacks support for closures.
If JavaScript did not have closures, then more states would have to be passed between functions explicitly, making parameter lists longer and code noisier. So, if you want a function to always have access to a private piece of state, you can use a closure.
You can create global array with callbacks. Add to this global array by register_func($name, $callback)
and call function by call_func($name, $parameter1, $parameter2, ...)
.
Without using eval
I think this is not possible to create named function from callback.
I managed to create one using evil eval
, ReflectionClass and SuperClosure library.
Here's my code:
<?php
function register_function(string $name, Closure $closure)
{
$serializedBody = (new SuperClosure\Serializer)->serialize($closure);
$obj = unserialize($serializedBody);
$reflection = new ReflectionClass($obj);
$property = $reflection->getProperty('data');
$property->setAccessible(true);
$data = $property->getValue($obj);
$body = preg_replace('/^function \(/', "function {$name} (", $data['code']);
eval($body);
}
$closure = function($a = 1, $b = 2, $c = 3) {
var_dump(compact('a', 'b', 'c'));
};
register_function('test', $closure);
var_dump(function_exists('test')); // true
test(13, 2, 3);
// array(3) {
// ["a"]=>
// int(13)
// ["b"]=>
// int(2)
// ["c"]=>
// int(3)
// }
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