Twig 不允许直接这样做。您可以向 Twig 添加一个简单的函数来处理闭包的执行,或者将您的闭包包装在一个类中以便能够使用 Twig 的属性函数(因为直接调用attribute(_context, 'myclosure', args)
将触发致命错误,因为 Twig 将直接返回闭包并忽略因为给定的参数_context
是一个数组)。
对于 Symfony 2.8+,实现此目的的简单 Twig 扩展看起来像这样。(对于 Symfony 4,请参阅新文档)
// src/AppBundle/Twig/Extension/CoreExtensions.php
namespace AppBundle\Twig\Extension;
class CoreExtensions extends \Twig_Extension
{
public function getFunctions()
{
return [
new \Twig_SimpleFunction('execute', [$this, 'executeClosure'])
];
}
public function executeClosure(\Closure $closure, $arguments)
{
return $closure(...$arguments);
}
public function getName()
{
return 'core_extensions_twig_extension';
}
}
然后,在您的模板中,您只需调用执行:
{{ execute(closure, [argument1, argument2]) }}
在不扩展 Twig 的情况下,解决此问题的一种方法是使用一个充当闭包包装器的类,并使用attribute
Twig 的函数,因为它可用于调用对象的方法。
// src/AppBundle/Twig/ClosureWrapper.php
namespace AppBundle\Twig;
/**
* Wrapper to get around the issue of not being able to use closures in Twig
* Since it is possible to call a method of a given object in Twig via "attribute",
* the only purpose of this class is to store the closure and give a method to execute it
*/
class ClosureWrapper
{
private $closure;
public function __construct($closure)
{
$this->closure = $closure;
}
public function execute()
{
return ($this->closure)(...func_get_args());
}
}
然后,你只需要在渲染时给你的模板一个 ClosureWrapper 实例,而不是闭包本身:
use AppBundle\Twig\ClosureWrapper;
class MyController extends Controller
{
public function myAction()
{
$localValue = 2;
$closure = new ClosureWrapper(function($param1, $param2) use ($localValue) {
return $localValue + $param1 + $param2;
});
return $this->render('mytemplate.html.twig', ['closure' => $closure]);
}
...
最终,在您的模板中,您需要使用attribute
来执行您在控制器中定义的闭包:
// Displays 12
{{ attribute(closure, 'execute', [4, 6]) }}
然而,这有点多余,因为在内部,attribute
Twig 的函数也会解包给定的参数。通过使用上面的代码,对于每次调用,参数都被依次解包、打包和再次解包。