Php 是否可以从闭包创建命名函数?
在PHP中,可以使用如下命名函数:Php 是否可以从闭包创建命名函数?,php,Php,在PHP中,可以使用如下命名函数: function foo() { return "bar"; } $foo = function() { return "bar"; }; 您可以使用如下的闭包: function foo() { return "bar"; } $foo = function() { return "bar"; }; 闭包非常棒,而且很容易创建,但不幸的是,我需要使用的库确实需要一个命名函数。是否可以从闭包动态创建命名函数?也就是说,不是提
function foo()
{
return "bar";
}
$foo = function() {
return "bar";
};
您可以使用如下的闭包:
function foo()
{
return "bar";
}
$foo = function() {
return "bar";
};
闭包非常棒,而且很容易创建,但不幸的是,我需要使用的库确实需要一个命名函数。是否可以从闭包动态创建命名函数?也就是说,不是提前在代码中定义所有函数,而是更像一个register\u函数($name,callable$closure)
我知道
create\u function
,但它将PHP字符串作为函数体,并只是eval
s它,这不是我想要的。您可以使用回调创建全局数组。通过register\u func($name,$callback)
添加到此全局数组,并通过call\u func($name,$parameter1,$parameter2,…)
调用函数
如果不使用
eval
我认为这不可能从回调创建命名函数。我不认为如果可以通过闭包动态创建命名函数,但使用类的神奇方法,您可能会发现此解决方法很有帮助:
<?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();
我的建议是使用静态方法,因为它们可以像简单函数一样被调用。我们可以用神奇的函数\uu 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);
我设法用邪恶的eval
和库创建了一个
这是我的密码:
<?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)
// }
简而言之,您不能在PHP中命名\Closure对象
虽然我确信有一个API可以做到这一点,但它并没有在PHP级别公开。你可以编写一个C插件来公开一个用户用php函数来命名这个函数。你说的“想要一个命名函数”是什么意思?你必须做library\u function('my\u func')
,然后它做function library\u function($func){$func();}
。不,库是Smarty,用例是注册插件。它会根据您提供的可调用类型对模板进行特定编译,而当前不支持闭包。它可以是实例方法、静态方法或命名函数。因此smarty需要命名函数,但您不想命名它?我不能命名它们,因为它们实际上是运行时定义的闭包。可以把它看作是foreach($things as$thing){$closureforthing($thing);registerClosure($closure);}
。无论如何,对于问题的范围来说,确切的用法有点太多了。我只是想知道这是否可能。如果没有,我将不得不等到相关问题得到解决。作为一般的良好实践,应该避免使用全局变量和名称空间。如果必须创建一个“上帝”数据对象,至少要创建它。@Pheagey这是一个简单的想法。我知道更好的解决方案是(例如)单例回调容器类。但我只想展示一个草案——不是一个完整的解决方案。啊,是的,很好。只是不想让OP养成坏习惯。继续:)@Pheagey我不明白-如果你有更好的解决方案,那就去吧!写下来!;)这似乎确实是不可能的,我最终实现了一些简单地调用适当闭包的对象。不过,您的解决方案更好,因为它不需要每次闭包都实例化一个额外的对象。@Skysplit我希望您这样做只是为了锻炼您的PHP知识,我们永远不会在任何实际项目中看到它。@d3jn我绝对不打算在任何项目中使用它:)检查(当时)很有趣!