mirror of
https://github.com/twigphp/Twig.git
synced 2026-09-14 19:36:43 +00:00
made a huge optimization for loops (again)
git-svn-id: http://svn.twig-project.org/trunk@118 93ef8e89-cb99-4229-a87c-7fa0fa45744b
This commit is contained in:
@@ -390,7 +390,11 @@ provided in a variable called `users`:
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
Inside of a for loop block you can access some special variables:
|
||||
>**NOTE**
|
||||
>A sequence can be either an array or an object implementing the `Iterator`
|
||||
>interface.
|
||||
|
||||
Inside of a `for` loop block you can access some special variables:
|
||||
|
||||
| Variable | Description
|
||||
| --------------------- | -------------------------------------------------------------
|
||||
@@ -402,7 +406,8 @@ Inside of a for loop block you can access some special variables:
|
||||
| `loop.last` | True if last iteration
|
||||
| `loop.length` | The number of items in the sequence
|
||||
|
||||
Unlike in PHP it's not possible to `break` or `continue` in a loop.
|
||||
>**NOTE**
|
||||
>Unlike in PHP it's not possible to `break` or `continue` in a loop.
|
||||
|
||||
If no iteration took place because the sequence was empty, you can render a
|
||||
replacement block by using `else`:
|
||||
@@ -412,10 +417,35 @@ replacement block by using `else`:
|
||||
{% for user in users %}
|
||||
<li>{{ user.username|e }}</li>
|
||||
{% else %}
|
||||
<li><em>no users found</em></li>
|
||||
<li><em>no user found</em></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
|
||||
By default, a loop iterates over the values of the sequence. You can iterate
|
||||
on keys by using the `keys` filter:
|
||||
|
||||
[twig]
|
||||
<h1>Members</h1>
|
||||
<ul>
|
||||
{% for key in users|keys %}
|
||||
<li>{{ key }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
You can also access both keys and values:
|
||||
|
||||
[twig]
|
||||
<h1>Members</h1>
|
||||
<ul>
|
||||
{% for key, value in users %}
|
||||
<li>{{ key }}: {{ user.username|e }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
>**NOTE**
|
||||
>On Twig before 0.9.3, you need to use the `items` filter to access both the
|
||||
>keys and values (`{% for key, value in users|items %}`).
|
||||
|
||||
### If
|
||||
|
||||
The `if` statement in Twig is comparable with the if statements of PHP. In the
|
||||
@@ -801,16 +831,6 @@ iterate over the keys of an array:
|
||||
...
|
||||
{% endfor %}
|
||||
|
||||
### `items`
|
||||
|
||||
The `items` filter is mainly useful when using the `for` tag to iterate over
|
||||
both the keys and the values of an array:
|
||||
|
||||
[twig]
|
||||
{% for key, value in array|items %}
|
||||
...
|
||||
{% endfor %}
|
||||
|
||||
### `escape`, `e`
|
||||
|
||||
The `escape` filter converts the characters `&`, `<`, `>`, `'`, and `"` in
|
||||
|
||||
@@ -18,7 +18,6 @@ class Twig_Extension_Core extends Twig_Extension
|
||||
public function initRuntime()
|
||||
{
|
||||
require_once dirname(__FILE__).'/../runtime.php';
|
||||
require_once dirname(__FILE__).'/../runtime_for.php';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+34
-22
@@ -58,13 +58,38 @@ class Twig_Node_For extends Twig_Node implements Twig_NodeListInterface
|
||||
$compiler->write("\$context['_iterated'] = false;\n");
|
||||
}
|
||||
|
||||
if ($this->isMultitarget)
|
||||
{
|
||||
$loopVars = array($this->item[0]->getName(), $this->item[1]->getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
$loopVars = array('_key', $this->item->getName());
|
||||
}
|
||||
|
||||
$var = rand(1, 999999);
|
||||
$compiler
|
||||
->write("\$seq$var = twig_iterator_to_array(")
|
||||
->subcompile($this->seq)
|
||||
->raw(");\n")
|
||||
->write("\$context['loop']['length'] = count(\$seq$var);\n")
|
||||
->write("for (\$i$var = 0; \$i$var < \$context['loop']['length']; \$i$var++)\n")
|
||||
|
||||
->write("\$context['loop'] = array(\n")
|
||||
->write(" 'parent' => \$context['_parent'],\n")
|
||||
->write(" 'length' => \$context['loop']['length'],\n")
|
||||
->write(" 'index0' => 0,\n")
|
||||
->write(" 'index' => 1,\n")
|
||||
->write(" 'revindex0' => \$context['loop']['length'] - 1,\n")
|
||||
->write(" 'revindex' => \$context['loop']['length'],\n")
|
||||
->write(" 'first' => true,\n")
|
||||
->write(" 'last' => false,\n")
|
||||
->write(");\n")
|
||||
|
||||
->write("foreach (\$seq$var as \$context[")
|
||||
->repr($loopVars[0])
|
||||
->raw("] => \$context[")
|
||||
->repr($loopVars[1])
|
||||
->raw("])\n")
|
||||
->write("{\n")
|
||||
->indent()
|
||||
;
|
||||
@@ -74,29 +99,16 @@ class Twig_Node_For extends Twig_Node implements Twig_NodeListInterface
|
||||
$compiler->write("\$context['_iterated'] = true;\n");
|
||||
}
|
||||
|
||||
$compiler->write("twig_set_loop_context(\$context, \$seq$var, \$i$var, ");
|
||||
|
||||
if ($this->isMultitarget)
|
||||
{
|
||||
$compiler->raw('array(');
|
||||
foreach ($this->item as $idx => $node)
|
||||
{
|
||||
if ($idx)
|
||||
{
|
||||
$compiler->raw(', ');
|
||||
}
|
||||
$compiler->repr($node->getName());
|
||||
}
|
||||
$compiler->raw(')');
|
||||
}
|
||||
else
|
||||
{
|
||||
$compiler->repr($this->item->getName());
|
||||
}
|
||||
|
||||
$compiler
|
||||
->raw(");\n")
|
||||
->subcompile($this->body)
|
||||
|
||||
->write("++\$context['loop']['index0'];\n")
|
||||
->write("++\$context['loop']['index'];\n")
|
||||
->write("--\$context['loop']['revindex0'];\n")
|
||||
->write("--\$context['loop']['revindex'];\n")
|
||||
->write("\$context['loop']['first'] = false;\n")
|
||||
->write("\$context['loop']['last'] = 0 === \$context['loop']['revindex0'];\n")
|
||||
|
||||
->outdent()
|
||||
->write("}\n")
|
||||
;
|
||||
|
||||
@@ -188,3 +188,26 @@ else
|
||||
return ucfirst(strtolower($string));
|
||||
}
|
||||
}
|
||||
|
||||
function twig_iterator_to_array($seq)
|
||||
{
|
||||
if (is_array($seq))
|
||||
{
|
||||
return $seq;
|
||||
}
|
||||
elseif (is_object($seq) && $seq instanceof Iterator)
|
||||
{
|
||||
return iterator_to_array($seq);
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
// only for backward compatibility
|
||||
function twig_get_array_items_filter($array)
|
||||
{
|
||||
// noop
|
||||
return $array;
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Twig.
|
||||
*
|
||||
* (c) 2009 Fabien Potencier
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
function twig_iterator_to_array($seq)
|
||||
{
|
||||
if (is_array($seq))
|
||||
{
|
||||
return array_values($seq);
|
||||
}
|
||||
elseif (is_object($seq) && $seq instanceof Iterator)
|
||||
{
|
||||
return iterator_to_array($seq, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
function twig_set_loop_context(&$context, $seq, $idx, $target)
|
||||
{
|
||||
if (is_array($target))
|
||||
{
|
||||
$context[$target[0]] = $seq[$idx][0];
|
||||
$context[$target[1]] = $seq[$idx][1];
|
||||
}
|
||||
else
|
||||
{
|
||||
$context[$target] = $seq[$idx];
|
||||
}
|
||||
|
||||
$context['loop'] = array(
|
||||
'parent' => $context['_parent'],
|
||||
'length' => $context['loop']['length'],
|
||||
'index0' => $idx,
|
||||
'index' => $idx + 1,
|
||||
'revindex0' => $context['loop']['length'] - $idx - 1,
|
||||
'revindex' => $context['loop']['length'] - $idx,
|
||||
'first' => $idx == 0,
|
||||
'last' => $idx + 1 == $context['loop']['length'],
|
||||
);
|
||||
}
|
||||
|
||||
function twig_get_array_items_filter($array)
|
||||
{
|
||||
if (!is_array($array) && (!is_object($array) || !$array instanceof Iterator))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = array();
|
||||
foreach ($array as $key => $value)
|
||||
{
|
||||
$result[] = array($key, $value);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
Reference in New Issue
Block a user