How can I use break or continue within for loop in Twig template? How can I use break or continue within for loop in Twig template? symfony symfony

How can I use break or continue within for loop in Twig template?


This can be nearly done by setting a new variable as a flag to break iterating:

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

An uglier, but working example for 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 %}

But there is no performance profit, only similar behaviour to the built-in break and continue statements like in flat PHP.


From docs TWIG 2.x docs:

Unlike in PHP, it's not possible to break or continue in a loop.

But still:

You can however filter the sequence during iteration which allows you to skip items.

Example 1 (for huge lists you can filter posts using slice, slice(start, length)):

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

Example 2 works TWIG 3.0 as well:

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

You can even use own TWIG filters for more complexed conditions, like:

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


A way to be able to use {% break %} or {% continue %} is to write TokenParsers for them.

I did it for the {% break %} token in the code below. You can, without much modifications, do the same thing for the {% 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")        ;    }}

Then you can simply use {% break %} to get out of loops like this:

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

To go even further, you may write token parsers for {% continue X %} and {% break X %} (where X is an integer >= 1) to get out/continue multiple loops like in PHP.