在PHP中,您可以使用以下命名函数:
function foo()
{
return "bar";
}
你可以拥有这样的闭包:
$foo = function() {
return "bar";
};
闭包非常棒且易于创建,但遗憾的是我需要使用的库真的需要一个命名函数。是否可以动态地从闭包创建命名函数?即没有提前在代码中定义所有函数,但更像是register_function($name, callable $closure)
。
我知道create_function
,但是那个人将PHP字符串作为函数体而只是eval
它,这不是我想要的。
答案 0 :(得分:8)
您可以使用回调创建全局数组。按register_func($name, $callback)
添加到此全局数组,并按call_func($name, $parameter1, $parameter2, ...)
调用函数。
不使用eval
我认为无法从回调创建命名函数。
答案 1 :(得分:4)
我设法使用邪恶的eval
,ReflectionClass和SuperClosure库创建了一个。
这是我的代码:
<?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)
// }
答案 2 :(得分:2)
我不认为是否可以动态创建闭包中的命名函数但是使用类的__call()
魔术方法,您可能会发现这种解决方法很有用:
<?php
class Foo
{
public function __call($name, $args)
{
if (isset($this->{$name}))
return call_user_func_array($this->{$name}, $args);
}
}
$foo = new Foo();
// Declaring a closure then assign it to $bar property of Foo
$foo->bar = function () {
echo "bar";
};
// Call Foo method of the same name
$foo->bar();
答案 3 :(得分:2)
我的建议是使用静态方法,因为它们可以像简单函数一样调用。我们可以使用魔术函数__callStatic
来实现此功能,如此代码
<?php
class FunctionsProvider
{
protected static $closures = [];
public static function addClosure($name, $closure)
{
if (is_callable($closure)) {
static::$closures[$name] = $closure;
} else {
throw new \Exception('Closure is not callable');
}
}
public static function __callStatic($name, $arguments)
{
if (array_key_exists($name, static::$closures)) {
return call_user_func_array(static::$closures[$name], $arguments);
} else {
throw new \Exception('Unknown method');
}
}
}
//Lets prepare sample closure
$foo = function() {
return "bar";
};
FunctionsProvider::addClosure('foo', $foo);
$return = FunctionsProvider::foo();
var_dump($return);
在输出上我们将得到
string(3)&#34; bar&#34;
答案 4 :(得分:1)
简而言之,你不能在PHP中命名一个\ Closure对象。
虽然我确信有一个API可以执行此操作,但它不会在PHP级别公开。有人可能会编写一个C插件来公开User-land php函数来命名函数。