Twig_SimpleFunction 可以修改上下文吗?
Can a Twig_SimpleFunction modify the context?
是否可以通过调用 Twig_SimpleFunction 来修改当前的 twig 上下文?
我注册了以下功能:
<?php
namespace Craft;
class TwiggedTwigExtension extends \Twig_Extension
{
public function getName()
{
return 'Twigged';
}
public function getFunctions()
{
return array(
'setContextVar' => new \Twig_SimpleFunction('setContextVar', array($this, 'setContextVar'), array('needs_context' => true)),
);
}
public function setContextVar($context, $str, $val)
{
$context['context'][$str] = $val;
var_dump(array_keys($context['context']));
}
}
从 {{ setContextVar('hellow', 'world') }}
这样的模板调用时,var_dump 显示修改后的上下文。但是像这样快速检查模板 {{ dump(_context|keys) }}
不会显示修改后的上下文。
我是不是做错了?
这对于函数是不可能的,因为上下文不是通过引用传递的。
在你的扩展中,你甚至访问了 $context['context']
,这意味着一个名为 context
的变量,而不是上下文本身(_context
是一个特殊的变量名,用于访问模板中的上下文,但它不会出现在发送给函数的上下文数组中,因为它本身就是数组)。
可能有一种方法可以通过更改节点 class 通过函数的自定义编译来执行此操作。但我还没有尝试过,它最终可能会有点难以维护表达式语义。
无论如何,我建议不要编写这样的函数。在 Twig 中分配变量没有函数语义,不能作为表达式的一部分完成(函数当然可以在表达式中使用)。更改此语义可能会导致奇怪的行为。
就像@DarkBee 在他的评论中提到的,您可以通过引用传递来修改上下文:
function setContextVar(&$context, ...)
但是,仅向 Twig 添加一个函数似乎不起作用(我使用的是 Twig 2.4.4):
$twig->addFunction(new Twig_Function('setContextVar', function(&$context, $name, $value) {
$context[$name] = $value;
}, ['needs_context' => true]));
当您在 Twig 文件中使用该函数时,上下文不会被修改,您会收到此警告:
Warning: Parameter 1 to {closure}() expected to be a reference, value
given in C:\...\vendor\twig\twig\lib\Twig\Environment.php(378) :
eval()'d code on line ...
相反,您需要创建一个 Twig 扩展:
$twig->addExtension(new class extends Twig_Extension {
public function getFunctions() {
return [
new Twig_Function('setContextVar', [$this, 'setContextVar'], ['needs_context' => true]),
];
}
public function setContextVar(&$context, $name, $value) {
$context[$name] = $value;
}
});
然后你可以在 Twig 中使用它而不会收到警告:
{{ dump() }}
{% do setContextVar('foo', 'bar') %}
{{ dump() }}
以上打印例如:
array(0) {
}
array(1) {
["foo"]=>
string(3) "bar"
}
是否可以通过调用 Twig_SimpleFunction 来修改当前的 twig 上下文?
我注册了以下功能:
<?php
namespace Craft;
class TwiggedTwigExtension extends \Twig_Extension
{
public function getName()
{
return 'Twigged';
}
public function getFunctions()
{
return array(
'setContextVar' => new \Twig_SimpleFunction('setContextVar', array($this, 'setContextVar'), array('needs_context' => true)),
);
}
public function setContextVar($context, $str, $val)
{
$context['context'][$str] = $val;
var_dump(array_keys($context['context']));
}
}
从 {{ setContextVar('hellow', 'world') }}
这样的模板调用时,var_dump 显示修改后的上下文。但是像这样快速检查模板 {{ dump(_context|keys) }}
不会显示修改后的上下文。
我是不是做错了?
这对于函数是不可能的,因为上下文不是通过引用传递的。
在你的扩展中,你甚至访问了 $context['context']
,这意味着一个名为 context
的变量,而不是上下文本身(_context
是一个特殊的变量名,用于访问模板中的上下文,但它不会出现在发送给函数的上下文数组中,因为它本身就是数组)。
可能有一种方法可以通过更改节点 class 通过函数的自定义编译来执行此操作。但我还没有尝试过,它最终可能会有点难以维护表达式语义。
无论如何,我建议不要编写这样的函数。在 Twig 中分配变量没有函数语义,不能作为表达式的一部分完成(函数当然可以在表达式中使用)。更改此语义可能会导致奇怪的行为。
就像@DarkBee 在他的评论中提到的,您可以通过引用传递来修改上下文:
function setContextVar(&$context, ...)
但是,仅向 Twig 添加一个函数似乎不起作用(我使用的是 Twig 2.4.4):
$twig->addFunction(new Twig_Function('setContextVar', function(&$context, $name, $value) {
$context[$name] = $value;
}, ['needs_context' => true]));
当您在 Twig 文件中使用该函数时,上下文不会被修改,您会收到此警告:
Warning: Parameter 1 to {closure}() expected to be a reference, value given in C:\...\vendor\twig\twig\lib\Twig\Environment.php(378) : eval()'d code on line ...
相反,您需要创建一个 Twig 扩展:
$twig->addExtension(new class extends Twig_Extension {
public function getFunctions() {
return [
new Twig_Function('setContextVar', [$this, 'setContextVar'], ['needs_context' => true]),
];
}
public function setContextVar(&$context, $name, $value) {
$context[$name] = $value;
}
});
然后你可以在 Twig 中使用它而不会收到警告:
{{ dump() }}
{% do setContextVar('foo', 'bar') %}
{{ dump() }}
以上打印例如:
array(0) {
}
array(1) {
["foo"]=>
string(3) "bar"
}