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:
fabien
2009-11-07 22:18:56 +00:00
parent 9cfb40b0fa
commit 588fb93097
5 changed files with 90 additions and 102 deletions
+33 -13
View File
@@ -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
-1
View File
@@ -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
View File
@@ -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")
;
+23
View File
@@ -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;
}
-66
View File
@@ -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;
}