Skip to content

Commit

Permalink
Latte: {foreach} optimized for speed
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Jan 23, 2012
1 parent 5c7c419 commit 7c3d3e3
Show file tree
Hide file tree
Showing 11 changed files with 61 additions and 50 deletions.
14 changes: 10 additions & 4 deletions Nette/Latte/Macros/CoreMacros.php
Expand Up @@ -56,7 +56,7 @@ public static function install(Latte\Compiler $compiler)
$me->addMacro('ifset', 'if (isset(%node.args)):', 'endif');
$me->addMacro('elseifset', 'elseif (isset(%node.args)):');

$me->addMacro('foreach', array($me, 'macroForeach'), '$iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its)');
$me->addMacro('foreach', '', array($me, 'macroEndForeach'));
$me->addMacro('for', 'for (%node.args):', 'endfor');
$me->addMacro('while', 'while (%node.args):', 'endwhile');
$me->addMacro('continueIf', 'if (%node.args) continue');
Expand Down Expand Up @@ -229,10 +229,16 @@ public function macroCaptureEnd(MacroNode $node, $writer)
/**
* {foreach ...}
*/
public function macroForeach(MacroNode $node, $writer)
public function macroEndForeach(MacroNode $node, $writer)
{
return '$iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator('
. preg_replace('#(.*)\s+as\s+#i', '$1) as ', $writer->formatArgs(), 1) . '):';
if (preg_match('#\W(\$iterator|include|require|get_defined_vars)\W#', $node->content)) {
$node->openingCode = '<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator('
. preg_replace('#(.*)\s+as\s+#i', '$1) as ', $writer->formatArgs(), 1) . '): ?>';
$node->closingCode = '<?php $iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>';
} else {
$node->openingCode = '<?php $iterations = 0; foreach (' . $writer->formatArgs() . '): ?>';
$node->closingCode = '<?php $iterations++; endforeach ?>';
}
}


Expand Down
20 changes: 14 additions & 6 deletions tests/Nette/Latte/CoreMacros.foreach.phpt
Expand Up @@ -20,9 +20,17 @@ CoreMacros::install($compiler);

$prefix = '<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator(';

Assert::same( $prefix . '$array) as $value): ?>', $compiler->expandMacro('foreach', '$array as $value')->openingCode );
Assert::same( $prefix . '$array) as $key => $value): ?>', $compiler->expandMacro('foreach', '$array as $key => $value')->openingCode );

Assert::same( $prefix . '$obj->data("A as B")) as $value): ?>', $compiler->expandMacro('foreach', '$obj->data("A as B") as $value')->openingCode );
Assert::same( $prefix . '$obj->data(\'A as B\')) as $value): ?>', $compiler->expandMacro('foreach', '$obj->data(\'A as B\') as $value')->openingCode );
Assert::same( $prefix . '$obj->data("X as Y, Z as W")) as $value): ?>', $compiler->expandMacro('foreach', '$obj->data("X as Y, Z as W") as $value')->openingCode );
function expandMacro($compiler, $args) {
$node = $compiler->expandMacro('foreach', $args);
$node->content = ' $iterator ';
$node->closing = TRUE;
$node->macro->nodeClosed($node);
return $node;
}

Assert::same( $prefix . '$array) as $value): ?>', expandMacro($compiler, '$array as $value')->openingCode );
Assert::same( $prefix . '$array) as $key => $value): ?>', expandMacro($compiler, '$array as $key => $value')->openingCode );

Assert::same( $prefix . '$obj->data("A as B")) as $value): ?>', expandMacro($compiler, '$obj->data("A as B") as $value')->openingCode );
Assert::same( $prefix . '$obj->data(\'A as B\')) as $value): ?>', expandMacro($compiler, '$obj->data(\'A as B\') as $value')->openingCode );
Assert::same( $prefix . '$obj->data("X as Y, Z as W")) as $value): ?>', expandMacro($compiler, '$obj->data("X as Y, Z as W") as $value')->openingCode );

This comment has been minimized.

Copy link
@fprochazka

fprochazka Jan 23, 2012

Contributor

U tohohle řádku mě napadá docela brutální feature :) Už jsem se párkrát setkal s tím, že jsem potřeboval procházet dvě pole zároveň.

{foreach $arr1 as $item, $arr2 as $key => $value}

Co myslíš @dg ? :) Možná je to přehnané...

This comment has been minimized.

Copy link
@dg

dg Jan 23, 2012

Author Member

To jsem asi nikdy nepotřeboval.

4 changes: 2 additions & 2 deletions tests/Nette/Latte/expected/macros.dynamicsnippets.phtml
Expand Up @@ -7,12 +7,12 @@ list($_l, $_g) = Nette\Latte\Macros\CoreMacros::initRuntime($template, 'xxx')
// block _outer
//
if (!function_exists($_l->blocks['_outer'][] = '_xxx__outer')) { function _xxx__outer($_l, $_args) { extract($_args); $_control->validateControl('outer')
;$iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator(array(1,2,3)) as $id): ?>
;$iterations = 0; foreach (array(1,2,3) as $id): ?>
<div id="<?php echo $_dynSnippetId = $_control->getSnippetId("inner-$id") ?>"><?php ob_start() ?>
#<?php echo Nette\Templating\Helpers::escapeHtml($id, ENT_NOQUOTES) ?>

<?php $_dynSnippets[$_dynSnippetId] = ob_get_flush() ?>
</div><?php $iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>
</div><?php $iterations++; endforeach ?>
<?php if (isset($_dynSnippets)) return $_dynSnippets;
}}

Expand Down
4 changes: 2 additions & 2 deletions tests/Nette/Latte/expected/macros.forms.formContainer.phtml
Expand Up @@ -22,9 +22,9 @@ Nette\Latte\Macros\FormMacros::renderFormBegin($form = $_form = $_control["myFor
<th>Checkboxes<th>
<td>
<?php $_formStack[] = $_form; $formContainer = $_form = $_form["cont2"] ?> <ol>
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($formContainer->controls) as $name => $field): ?>
<?php $iterations = 0; foreach ($formContainer->controls AS $name => $field): ?>
<li><?php echo $_form[$name]->getControl()->addAttributes(array()) ?> - <?php if ($_label = $_form[$name]->getLabel()) echo $_label->addAttributes(array()) ?></li>
<?php $iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?> </ol>
<?php $iterations++; endforeach ?> </ol>
<?php $_form = array_pop($_formStack) ?>
</td>
</tr>
Expand Down
4 changes: 2 additions & 2 deletions tests/Nette/Latte/expected/macros.forms.phtml
Expand Up @@ -2,12 +2,12 @@
%A%
Nette\Latte\Macros\FormMacros::renderFormBegin($form = $_form = $_control["myForm"], array()) ?>
<table>
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($form->controls) as $name => $field): ?>
<?php $iterations = 0; foreach ($form->controls as $name => $field): ?>
<tr>
<th><?php if ($_label = $_form[$name]->getLabel()) echo $_label->addAttributes(array()) ?><th>
<td><?php echo $_form[$name]->getControl()->addAttributes(array('title' => 'Hello', 'cols' => 10)) ?></td>
</tr>
<?php $iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>
<?php $iterations++; endforeach ?>
</table>
<?php Nette\Latte\Macros\FormMacros::renderFormEnd($_form) ?>

Expand Down
19 changes: 9 additions & 10 deletions tests/Nette/Latte/expected/macros.general.html.phtml
Expand Up @@ -22,9 +22,9 @@ if (!function_exists($_l->blocks['menu'][] = '_xxx_menu')) { function _xxx_menu(
//
if (!function_exists($_l->blocks['bl'][] = '_xxx_bl')) { function _xxx_bl($_l, $_args) { extract($_args)
?><ul title="block + if + foreach">
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): if (strlen($person)===4): ?>
<?php $iterations = 0; foreach ($people as $person): if (strlen($person)===4): ?>
<li><?php echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ?></li>
<?php endif ;$iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>
<?php endif ;$iterations++; endforeach ?>
</ul>
<?php
}}
Expand Down Expand Up @@ -179,9 +179,8 @@ call_user_func(reset($_l->blocks['menu']), $_l, get_defined_vars()) ?>


<ul title="foreach">
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): ?>
<li><?php echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ?></li>
<?php $iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>
<?php $iterations = 0; foreach ($people as $person): ?> <li><?php echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ?></li>
<?php $iterations++; endforeach ?>
</ul>

<ul title="for">
Expand Down Expand Up @@ -218,20 +217,20 @@ call_user_func(reset($_l->blocks['menu']), $_l, get_defined_vars()) ?>
<?php endif ?>

<ul title="if + foreach">
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): if (strlen($person)===4): ?>
<?php $iterations = 0; foreach ($people as $person): if (strlen($person)===4): ?>
<li><?php echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ?></li>
<?php endif ;$iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>
<?php endif ;$iterations++; endforeach ?>
</ul>

<ul title="if + inner-if + inner-foreach">
<?php if (empty($iterator)): ?> <li><?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): if (strlen($person)===4): echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ;endif ;$iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?></li>
<?php if (empty($iterator)): ?> <li><?php $iterations = 0; foreach ($people as $person): if (strlen($person)===4): echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ;endif ;$iterations++; endforeach ?></li>
<?php endif ?>
</ul>

<ul title="inner-if + inner-foreach">
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): if (strlen($person)===4): ?>
<?php $iterations = 0; foreach ($people as $person): if (strlen($person)===4): ?>
<li><?php echo Nette\Templating\Helpers::escapeHtml($template->lower($person), ENT_NOQUOTES) ?></li>
<?php endif ;$iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?></ul>
<?php endif ;$iterations++; endforeach ?></ul>

<?php call_user_func(reset($_l->blocks['bl']), $_l, get_defined_vars()) ?>

Expand Down
21 changes: 10 additions & 11 deletions tests/Nette/Latte/expected/macros.general.xhtml.phtml
Expand Up @@ -22,9 +22,9 @@ if (!function_exists($_l->blocks['menu'][] = '_xxx_menu')) { function _xxx_menu(
//
if (!function_exists($_l->blocks['bl'][] = '_xxx_bl')) { function _xxx_bl($_l, $_args) { extract($_args)
?><ul title="block + if + foreach">
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): if (strlen($person)===4): ?>
<?php $iterations = 0; foreach ($people as $person): if (strlen($person)===4): ?>
<li><?php echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ?></li>
<?php endif ;$iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>
<?php endif ;$iterations++; endforeach ?>
</ul>
<?php
}}
Expand Down Expand Up @@ -175,9 +175,8 @@ call_user_func(reset($_l->blocks['menu']), $_l, get_defined_vars()) ?>


<ul title="foreach">
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): ?>
<li><?php echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ?></li>
<?php $iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>
<?php $iterations = 0; foreach ($people as $person): ?> <li><?php echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ?></li>
<?php $iterations++; endforeach ?>
</ul>

<ul title="for">
Expand Down Expand Up @@ -214,20 +213,20 @@ call_user_func(reset($_l->blocks['menu']), $_l, get_defined_vars()) ?>
<?php endif ?>

<ul title="if + foreach">
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): if (strlen($person)===4): ?>
<?php $iterations = 0; foreach ($people as $person): if (strlen($person)===4): ?>
<li><?php echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ?></li>
<?php endif ;$iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>
<?php endif ;$iterations++; endforeach ?>
</ul>

<ul title="if + inner-if + inner-foreach">
<?php if (empty($iterator)): ?> <li><?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): if (strlen($person)===4): echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ;endif ;$iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?></li>
<?php if (empty($iterator)): ?> <li><?php $iterations = 0; foreach ($people as $person): if (strlen($person)===4): echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ;endif ;$iterations++; endforeach ?></li>
<?php endif ?>
</ul>

<ul title="inner-if + inner-foreach">
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): if (strlen($person)===4): ?>
<?php $iterations = 0; foreach ($people as $person): if (strlen($person)===4): ?>
<li><?php echo Nette\Templating\Helpers::escapeHtml($template->lower($person), ENT_NOQUOTES) ?></li>
<?php endif ;$iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?></ul>
<?php endif ;$iterations++; endforeach ?></ul>

<?php call_user_func(reset($_l->blocks['bl']), $_l, get_defined_vars()) ?>

Expand Down Expand Up @@ -257,4 +256,4 @@ normal<?php if (false): ?></b>

<?php ob_start() ?>FALSE<?php if (FALSE) ob_end_flush(); else ob_end_clean() ?>

<?php ob_start() ?>TRUE<?php ob_start() ?>FALSE<?php if (TRUE) { ob_end_clean(); ob_end_flush(); } else { $_else = ob_get_contents(); ob_end_clean(); ob_end_clean(); echo $_else; } ?>
<?php ob_start() ?>TRUE<?php ob_start() ?>FALSE<?php if (TRUE) { ob_end_clean(); ob_end_flush(); } else { $_else = ob_get_contents(); ob_end_clean(); ob_end_clean(); echo $_else; } ?>
Expand Up @@ -15,9 +15,9 @@ if (!function_exists($_l->blocks['title'][] = '_xxx_title')) { function _xxx_tit
//
if (!function_exists($_l->blocks['content'][] = '_xxx_content')) { function _xxx_content($_l, $_args) { extract($_args)
?> <ul>
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): ?>
<?php $iterations = 0; foreach ($people as $person): ?>
<li><?php echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ?></li>
<?php $iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>
<?php $iterations++; endforeach ?>
</ul>
<?php
}}
Expand Down
4 changes: 2 additions & 2 deletions tests/Nette/Latte/expected/macros.inheritance.child2.phtml
Expand Up @@ -10,9 +10,9 @@ if (!function_exists($_l->blocks['content'][] = '_xxx_content')) { function _xxx
?> <h1><?php call_user_func(reset($_l->blocks['title']), $_l, get_defined_vars()) ?></h1>

<ul>
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): ?>
<?php $iterations = 0; foreach ($people as $person): ?>
<li><?php echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ?></li>
<?php $iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>
<?php $iterations++; endforeach ?>
</ul>
<?php
}}
Expand Down
12 changes: 6 additions & 6 deletions tests/Nette/Latte/expected/macros.syntax.phtml
Expand Up @@ -14,26 +14,26 @@ if (%A%}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<ul>
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): ?>
<?php $iterations = 0; foreach ($people as $person): ?>
<li><?php echo Nette\Templating\Helpers::escapeHtml($template->upper($person), ENT_NOQUOTES) ?></li>
<?php $iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>
<?php $iterations++; endforeach ?>
{* comment latte *}
</ul>

<p>Default: <?php echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ?></p>

<ul>
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): ?>
<?php $iterations = 0; foreach ($people as $person): ?>
<li><?php echo Nette\Templating\Helpers::escapeHtml($template->upper($person), ENT_NOQUOTES) ?></li>
<?php $iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>
<?php $iterations++; endforeach ?>
</ul>

<p>Default: <?php echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ?></p>

<ul>
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): ?>
<?php $iterations = 0; foreach ($people as $person): ?>
<li><?php echo Nette\Templating\Helpers::escapeHtml($template->upper($person), ENT_NOQUOTES) ?></li>
<?php $iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>
<?php $iterations++; endforeach ?>
</ul>

<p>Default: <?php echo Nette\Templating\Helpers::escapeHtml($person, ENT_NOQUOTES) ?></p>
Expand Down
5 changes: 2 additions & 3 deletions tests/Nette/Latte/expected/macros.xml.phtml
Expand Up @@ -58,9 +58,8 @@ var html = <?php echo Nette\Templating\Helpers::escapeXml($el) ?>;


<ul>
<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator($people) as $person): ?>
<li><?php echo Nette\Templating\Helpers::escapeXml($person) ?></li>
<?php $iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>
<?php $iterations = 0; foreach ($people as $person): ?> <li><?php echo Nette\Templating\Helpers::escapeXml($person) ?></li>
<?php $iterations++; endforeach ?>
</ul>

<?php if (true): ?><p>
Expand Down

0 comments on commit 7c3d3e3

Please sign in to comment.