我尝试使用一个简单的循环,在我的实际代码中,这个循环更加复杂,我需要break
像这样的迭代:
{% for post in posts %}
{% if post.id == 10 %}
{# break #}
{% endif %}
<h2>{{ post.heading }}</h2>
{% endfor %}
我如何使用的行为,break
或continue
在枝杈PHP控制结构?
Answers:
通过将新变量设置为迭代标志,几乎可以完成此操作break
:
{% set break = false %}
{% for post in posts if not break %}
<h2>{{ post.heading }}</h2>
{% if post.id == 10 %}
{% set break = true %}
{% endif %}
{% endfor %}
一个丑陋但可行的示例continue
:
{% set continue = false %}
{% for post in posts %}
{% if post.id == 10 %}
{% set continue = true %}
{% endif %}
{% if not continue %}
<h2>{{ post.heading }}</h2>
{% endif %}
{% if continue %}
{% set continue = false %}
{% endif %}
{% endfor %}
但是没有性能收益,只有与内置PHP
break
和continue
类似内部PHP语句类似的行为。
first
树枝过滤器:twig.sensiolabs.org/doc/filters/first.html
set break = true
在最后加上if语句。但是,是的,这取决于您的代码,因此感谢您对其进行澄清
从文档TWIG 文档:
与PHP不同,它不可能中断或继续循环。
但仍然:
但是,您可以在迭代过程中过滤序列,从而可以跳过项目。
示例1(对于庞大的列表,您可以使用slice,过滤帖子slice(start, length)
):
{% for post in posts|slice(0,10) %}
<h2>{{ post.heading }}</h2>
{% endfor %}
范例2:
{% for post in posts if post.id < 10 %}
<h2>{{ post.heading }}</h2>
{% endfor %}
您甚至可以针对更复杂的情况使用自己的TWIG过滤器,例如:
{% for post in posts|onlySuperPosts %}
<h2>{{ post.heading }}</h2>
{% endfor %}
{% for post in posts|slice(0,10) %}
Unlike in PHP, it's not possible to break or continue in a loop.
在阅读文档时错过了。但是我认为break
并且continue
是一个很好的功能,需要添加
for
第一次击中后应该是易碎的。@VictorBocharsky的答案是正确的
{% for post in posts|slice(0,10) %}
获取大量列表。看到我的第一条评论。我也更新了答案。
一种可以使用{% break %}
或为它们{% continue %}
编写TokenParser
的方法。
我是{% break %}
在下面的代码中为令牌做的。您无需做太多修改就可以对进行相同的操作{% continue %}
。
AppBundle \ Twig \ AppExtension.php:
namespace AppBundle\Twig;
class AppExtension extends \Twig_Extension
{
function getTokenParsers() {
return array(
new BreakToken(),
);
}
public function getName()
{
return 'app_extension';
}
}
AppBundle \ Twig \ BreakToken.php:
namespace AppBundle\Twig;
class BreakToken extends \Twig_TokenParser
{
public function parse(\Twig_Token $token)
{
$stream = $this->parser->getStream();
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
// Trick to check if we are currently in a loop.
$currentForLoop = 0;
for ($i = 1; true; $i++) {
try {
// if we look before the beginning of the stream
// the stream will throw a \Twig_Error_Syntax
$token = $stream->look(-$i);
} catch (\Twig_Error_Syntax $e) {
break;
}
if ($token->test(\Twig_Token::NAME_TYPE, 'for')) {
$currentForLoop++;
} else if ($token->test(\Twig_Token::NAME_TYPE, 'endfor')) {
$currentForLoop--;
}
}
if ($currentForLoop < 1) {
throw new \Twig_Error_Syntax(
'Break tag is only allowed in \'for\' loops.',
$stream->getCurrent()->getLine(),
$stream->getSourceContext()->getName()
);
}
return new BreakNode();
}
public function getTag()
{
return 'break';
}
}
AppBundle \ Twig \ BreakNode.php:
namespace AppBundle\Twig;
class BreakNode extends \Twig_Node
{
public function compile(\Twig_Compiler $compiler)
{
$compiler
->write("break;\n")
;
}
}
然后,您可以简单地使用{% break %}
来摆脱这种循环:
{% for post in posts %}
{% if post.id == 10 %}
{% break %}
{% endif %}
<h2>{{ post.heading }}</h2>
{% endfor %}
更进一步,您可以为{% continue X %}
和编写令牌解析器{% break X %}
(其中X是大于等于1的整数)以退出/继续多个循环(如PHP中)。
我找到了一个继续的好方法(喜欢上面的break示例)。在这里,我不想列出“代理商”。在PHP中,我会“继续”,但在树枝中,我想出了另一种选择:
{% for basename, perms in permsByBasenames %}
{% if basename == 'agency' %}
{# do nothing #}
{% else %}
<a class="scrollLink" onclick='scrollToSpot("#{{ basename }}")'>{{ basename }}</a>
{% endif %}
{% endfor %}
或者如果不符合我的标准,我就跳过它:
{% for tr in time_reports %}
{% if not tr.isApproved %}
.....
{% endif %}
{% endfor %}