【问题标题】:How can I use break or continue within for loop in Twig template?如何在 Twig 模板的 for 循环中使用 break 或 continue?
【发布时间】:2014-03-07 12:34:27
【问题描述】:

我尝试使用一个简单的循环,在我的真实代码中这个循环更复杂,我需要break这个迭代像:

{% for post in posts %}
    {% if post.id == 10 %}
        {# break #}
    {% endif %}
    <h2>{{ post.heading }}</h2>
{% endfor %}

如何在 Twig 中使用 PHP 控制结构的 breakcontinue 的行为?

【问题讨论】:

    标签: php symfony for-loop twig break


    【解决方案1】:

    来自文档 TWIG 2.x docs

    与 PHP 不同,不能在循环中中断或继续。

    但还是:

    但是,您可以在迭代期间过滤序列,从而允许您跳过项目。

    示例 1(对于大型列表,您可以使用 sliceslice(start, length) 过滤帖子):

    {% for post in posts|slice(0,10) %}
        <h2>{{ post.heading }}</h2>
    {% endfor %}
    

    示例 2 也适用于 TWIG 3.0:

    {% for post in posts if post.id < 10 %}
        <h2>{{ post.heading }}</h2>
    {% endfor %}
    

    您甚至可以使用自己的TWIG filters 处理更复杂的情况,例如:

    {% for post in posts|onlySuperPosts %}
        <h2>{{ post.heading }}</h2>
    {% endfor %}
    

    【讨论】:

    • 此外,如果您想在 10 次迭代后实现中断循环,您可以这样使用:{% for post in posts|slice(0,10) %}
    • 好的,谢谢,我在阅读文档时可能错过了Unlike in PHP, it's not possible to break or continue in a loop.。但是我觉得breakcontinue是个不错的功能,需要添加
    • 循环语句中不能访问循环变量!
    • 不起作用。很长的列表,for 在第一次被击中后应该是易碎的。 @VictorBocharsky 的答案是正确的
    • 请注意,虽然它在 2.0 中可用,但 Twig 在 3.0 版本中删除了 {% for ... if ... %} 语句。
    【解决方案2】:

    这可以几乎通过将新变量设置为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 %}
    

    但是没有性能收益,只有与内置的breakcontinue 语句类似的行为,如平面PHP。

    【讨论】:

    • 很有用。就我而言,我只需要显示/获得第一个结果。 Twig 有没有办法获得第一个值?这只是为了更好的性能目的。
    • @pathros 为了获得第一个值,使用first twig 过滤器:twig.sensiolabs.org/doc/filters/first.html
    • 喜欢这张纸条。在过去的 10 分钟里一直在尝试找到一些没有帮助的东西:D
    • 值得注意的是,这不会中断代码执行,任何低于set break = true 的东西都会被执行,除非你把它放在else 语句中。见twigfiddle.com/euio5w
    • @Gus 是的,这就是为什么我打算将带有 set break = true 的 if 语句放在最 end 的原因。但是,是的,这取决于您的代码,所以感谢您提及它以澄清
    【解决方案3】:

    能够使用{% break %}{% continue %} 的一种方法是为它们编写TokenParsers。

    我在下面的代码中为{% 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)编写令牌解析器到get out/continue multiple loops like in PHP

    【讨论】:

    • 这太过分了。 Twig 循环应该支持中断并原生地继续。
    • 如果您不想/不能使用过滤器,这很好。
    • squirrelphp/twig-php-syntax library 提供{% break %}{% break n %}{% continue %} 令牌。
    • @mtsknn 和作者使用并改进了我为此答案编写的代码!
    • @JulesLamur,你说“@mtsknn 和作者”,但我不参与那个图书馆。
    【解决方案4】:

    来自@NHG 评论——完美运行

    {% for post in posts|slice(0,10) %}
    

    【讨论】:

    • @Basit 如果帖子按日期排序?
    【解决方案5】:

    我找到了一个很好的解决方法来继续(喜欢上面的中断示例)。 这里我不想列出“机构”。在 PHP 中我会“继续”,但在 twig 中,我想出了替代方案:

    {% 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 %}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-11-11
      • 1970-01-01
      • 2023-03-04
      • 1970-01-01
      • 2017-02-02
      • 2018-08-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多