twig - 将函数传递给模板

Sto*_*art 23 php inheritance template-engine function twig

目前,我将我的函数放在一个类中,并将此类的实例传递给模板,并将我所需的函数作为类方法调用.

{{ unneededclass.blah() }}
Run Code Online (Sandbox Code Playgroud)

我需要像下面这样做

{{ blah() }}
Run Code Online (Sandbox Code Playgroud)

可能吗?

Aus*_*yde 33

2015年5月14日更新

评论者指出,我大多错了.如果您确实需要一个函数,而不是一个过滤器或宏,您可以按照Twig文档中的建议进行操作:

$twig = new Twig_Environment($loader);
$function = new Twig_SimpleFunction('blah', function () {
   // ...
});
$twig->addFunction($function);
Run Code Online (Sandbox Code Playgroud)

并使用像

{{ blah() }}
Run Code Online (Sandbox Code Playgroud)

简而言之,不,这是不可能的.

但是,希望不会丢失!

过滤器

如果blah()你的这个函数是为了修改现有变量,那么它就是一个过滤器.

一个例子:

//in your PHP
function format_date($date_string,$format_string) {
    return date($format_string,strtotime($date_string));
}
$twig_env->addFilter('format_date',new Twig_Filter_Function('format_date'));

{# in your template #}
{{ some_date|format_date('n/j/Y') }}
Run Code Online (Sandbox Code Playgroud)

(第一个参数是您要过滤的变量,第二个参数是通过常规方式提供的)

如上所述,如果您的函数只输出HTML,那么它就是宏的一个很好的候选者.

一个例子:

{# in your template #}
{% macro say_hello() %}
<p>Oh! Hello, world!</p>
{% endmacro %}

{# ... later on ... #}
{{ _self.say_hello() }}
Run Code Online (Sandbox Code Playgroud)

或者带参数:

{% macro input(name,value,type) %}
<input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value }}">
{% endmacro %}

{{ _self.input('phone_number','867-5309') }}
{{ _self.input('subscribe','yes','checkbox') }}
Run Code Online (Sandbox Code Playgroud)

为什么?

要记住的是,根据MVC ,Twig模板代表一个视图.这意味着它们在环境方面是孤立的,并且只能通过您在方法中传递的数据数组来表示传递它们的上下文$template->render().

这是一件好事,因为它将您的演示文稿与逻辑和数据分离开来.如果你可以任意调用函数,那么你突然增加了耦合,这是一件坏事.

另一个原因是PHP处理回调的方式.考虑一下如何将该功能传递到模板中......可能是这样的:

function blah() {
    return "<p>Oh! Hello, world!</p>";
}

$template = $twig_env->loadTemplate('template.html');
echo $template->render(array('blah'=>'blah'));
Run Code Online (Sandbox Code Playgroud)

在您的模板中,上下文变量blah现在只是一个包含的字符串'blah'.

在vanilla PHP中,当你使用这样的变量函数时(尝试使用类似函数的字符串变量),它(或多或少)执行该函数的查找,然后调用它.你没有传递这个功能,只是它的名字.

问题是,您不可能将函数传递给模板,因为PHP执行此操作的唯一机制是通过名称字符串,并且一旦进入模板,该名称就不再是函数名称而只是一个字符串.

有点长啰嗦,但我希望有所帮助!

如果您需要更多文档,官方文档就在这里.

  • Twig也支持函数,在某些情况下需要它http://twig.sensiolabs.org/doc/advanced.html#functions (3认同)

小智 6

我和你的朋友一样迷茫,但在网上搜索答案后却没有找到答案,我决定看看自己是否能做到.因此,我想在这里发布我的解决方案(即使我知道这篇文章是旧的),因为如果你搜索这个问题,这是谷歌的第一次点击.

在这里,它实际上非常简单:

我创建了一个包含我的函数和变量的类,例如:

class functionContainer{
        function getRandomNumber()
        {
                return rand();
        }
}
$values = array(
'functions'=> new functionContainer()
);
Run Code Online (Sandbox Code Playgroud)

所以现在我们将$ value作为一个数组,其中包含带有函数"getRandomNumber()"的对象.

渲染模板文件时,请将此类包含为值:

$twig->render('random.html', $values);
Run Code Online (Sandbox Code Playgroud)

这样,在模板文件中,您可以调用此方法来调用函数并获取结果:

{{ functions.getRandomNumber }}
Run Code Online (Sandbox Code Playgroud)


Pla*_*ski 6

虽然你不能直接PHP调用,但twig是可扩展的.您可以添加一个可调用的过滤器,这样您就可以应用于传递给模板的PHP函数.

namespace My\Twig\Extension;

class LambdaFilter extends \Twig_Extension {

    public function getName() {
        return 'lambda_filter';
    }

    public function getFilters() {
        return array(
            new \Twig_SimpleFilter('call', array($this, 'doCall'))
        );
    }

    public function doCall() {
        $arguments = func_get_args();
        $callable = array_shift($arguments);
        if(!is_callable($callable)) {
            throw new InvalidArgumentException();
        }
        return call_user_func_array($callable, $arguments);
    }

}
Run Code Online (Sandbox Code Playgroud)

现在,如果您将变量传递my_func给模板,则可以执行此操作my_func|call(arg1, arg2).您甚至可以执行更高阶的函数,"array_filter"|call(my_array, my_func)并且您总是可以在过滤器中执行更多操作,例如将数组作为参数接受等等.