diff --git a/change_log.txt b/change_log.txt index a963f340..af5db492 100644 --- a/change_log.txt +++ b/change_log.txt @@ -1,4 +1,7 @@  ===== 3.1.30-dev ===== (xx.xx.xx) + 28.12.2015 + - optimization of {foreach} code size and processing + 27.12.2015 - improve inheritance code - update external methods diff --git a/libs/Smarty.class.php b/libs/Smarty.class.php index f1c5bdad..d1093f78 100644 --- a/libs/Smarty.class.php +++ b/libs/Smarty.class.php @@ -121,7 +121,7 @@ class Smarty extends Smarty_Internal_TemplateBase /** * smarty version */ - const SMARTY_VERSION = '3.1.30-dev/11'; + const SMARTY_VERSION = '3.1.30-dev/12'; /** * define variable scopes diff --git a/libs/sysplugins/smarty_internal_compile_foreach.php b/libs/sysplugins/smarty_internal_compile_foreach.php index 178a0a52..74ed9f7f 100644 --- a/libs/sysplugins/smarty_internal_compile_foreach.php +++ b/libs/sysplugins/smarty_internal_compile_foreach.php @@ -92,32 +92,33 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_Compile_Private_Fo $this->isNamed = false; // check and get attributes $_attr = $this->getAttributes($compiler, $args); - $from = $_attr['from']; - $item = $compiler->getId($_attr['item']); + $from = $_attr[ 'from' ]; + $item = $compiler->getId($_attr[ 'item' ]); if ($item === false) { - $item = $compiler->getVariableName($_attr['item']); + $item = $compiler->getVariableName($_attr[ 'item' ]); } + $key = $name = null; $attributes = array('item' => $item); - if (isset($_attr['key'])) { - $key = $compiler->getId($_attr['key']); + if (isset($_attr[ 'key' ])) { + $key = $compiler->getId($_attr[ 'key' ]); if ($key === false) { - $key = $compiler->getVariableName($_attr['key']); + $key = $compiler->getVariableName($_attr[ 'key' ]); } - $attributes['key'] = $key; + $attributes[ 'key' ] = $key; } - if (isset($_attr['name'])) { + if (isset($_attr[ 'name' ])) { $this->isNamed = true; - $attributes['name'] = $compiler->getId($_attr['name']); + $name = $attributes[ 'name' ] = $compiler->getId($_attr[ 'name' ]); } foreach ($attributes as $a => $v) { if ($v === false) { $compiler->trigger_template_error("'{$a}' attribute/variable has illegal value", null, true); } } - $fromName = $compiler->getVariableName($_attr['from']); + $fromName = $compiler->getVariableName($_attr[ 'from' ]); if ($fromName) { foreach (array('item', 'key') as $a) { - if (isset($attributes[$a]) && $attributes[$a] == $fromName) { + if (isset($attributes[ $a ]) && $attributes[ $a ] == $fromName) { $compiler->trigger_template_error("'{$a}' and 'from' may not have same variable name '{$fromName}'", null, true); } @@ -125,147 +126,100 @@ class Smarty_Internal_Compile_Foreach extends Smarty_Internal_Compile_Private_Fo } $itemVar = "\$_smarty_tpl->tpl_vars['{$item}']"; - $local = '$__foreach_' . (isset($attributes['name']) ? $attributes['name'] : $attributes['item']) . '_' . - $this->counter ++ . '_'; - $needIteration = false; + $local = '$__foreach_' . $attributes[ 'item' ] . '_' . $this->counter ++ . '_'; // search for used tag attributes $itemAttr = array(); $namedAttr = array(); $this->scanForProperties($attributes, $compiler); - if (!empty($this->matchResults['item'])) { - $itemAttr = $this->matchResults['item']; + if (!empty($this->matchResults[ 'item' ])) { + $itemAttr = $this->matchResults[ 'item' ]; } - if (!empty($this->matchResults['named'])) { - $namedAttr = $this->matchResults['named']; + if (!empty($this->matchResults[ 'named' ])) { + $namedAttr = $this->matchResults[ 'named' ]; } - if (isset($itemAttr['last'])) { - $needIteration = true; + if (isset($itemAttr[ 'first' ])) { + $itemAttr[ 'index' ] = true; } - if (isset($namedAttr['last'])) { - $needIteration = true; + if (isset($namedAttr[ 'first' ])) { + $namedAttr[ 'index' ] = true; + } + if (isset($namedAttr[ 'last' ])) { + $namedAttr[ 'iteration' ] = true; + $namedAttr[ 'total' ] = true; + } + if (isset($itemAttr[ 'last' ])) { + $itemAttr[ 'iteration' ] = true; + $itemAttr[ 'total' ] = true; } - $keyTerm = ''; - if (isset($itemAttr['key'])) { + if (isset($itemAttr[ 'key' ])) { $keyTerm = "{$itemVar}->key => "; - } elseif (isset($attributes['key'])) { + } elseif (isset($attributes[ 'key' ])) { $keyTerm = "\$_smarty_tpl->tpl_vars['{$key}']->value => "; } - - $saveVars = array(); - $restoreVars = array(); if ($this->isNamed) { $foreachVar = "\$_smarty_tpl->tpl_vars['__smarty_foreach_{$attributes['name']}']"; - if (!empty($namedAttr)) { - $saveVars['saved'] = "isset({$foreachVar}) ? {$foreachVar} : false;"; - $restoreVars[] = "if ({$local}saved) {\n{$foreachVar} = {$local}saved;\n}\n"; - } } - foreach (array('item', 'key') as $a) { - if (isset($attributes[$a])) { - $saveVars['saved_' . $a] = - "isset(\$_smarty_tpl->tpl_vars['{$attributes[$a]}']) ? \$_smarty_tpl->tpl_vars['{$attributes[$a]}'] : false;"; - $restoreVars[] = - "if ({$local}saved_{$a}) {\n\$_smarty_tpl->tpl_vars['{$attributes[$a]}'] = {$local}saved_{$a};\n}\n"; - } - } - $this->openTag($compiler, 'foreach', - array('foreach', $compiler->nocache, $local, $restoreVars, $itemVar, true)); + $this->openTag($compiler, 'foreach', array('foreach', $compiler->nocache, $local, $itemVar, true)); // maybe nocache because of nocache variables $compiler->nocache = $compiler->nocache | $compiler->tag_nocache; - + $needTotal = isset($itemAttr[ 'show' ]) || isset($itemAttr[ 'total' ]) || isset($namedAttr[ 'total' ]) || + isset($namedAttr[ 'show' ]) || isset($itemAttr[ 'last' ]) || isset($namedAttr[ 'last' ]); // generate output code $output = " $code) { - $output .= "{$local}{$k} = {$code}\n"; + $output .= "\$_from = \$_smarty_tpl->smarty->ext->_foreach->init(\$_smarty_tpl, $from, " . + var_export($item, true); + if ($name || $needTotal || $key) { + $output .= ', ' . var_export($needTotal, true); } - if (isset($itemAttr['show']) || isset($itemAttr['total']) || isset($namedAttr['total']) || isset($namedAttr['show']) || isset($itemAttr['last']) || isset($namedAttr['last'])) { - $output .= "{$local}total = \$_smarty_tpl->smarty->ext->_foreach->count(\$_from);\n"; + if ($name || $key) { + $output .= ', ' . var_export($key, true); } - $output .= "{$itemVar} = new Smarty_Variable();\n"; - if (isset($itemAttr['show'])) { - $output .= "{$itemVar}->show = ({$local}total > 0);\n"; + if ($name) { + $output .= ', ' . var_export($name, true) . ', ' . var_export($namedAttr, true); } - if (isset($itemAttr['total'])) { - $output .= "{$itemVar}->total= {$local}total;\n"; + $output .= ");\n"; + if (isset($itemAttr[ 'show' ])) { + $output .= "{$itemVar}->show = ({$itemVar}->total > 0);\n"; } - if ($this->isNamed) { - $prop = array(); - if (isset($namedAttr['total'])) { - $prop['total'] = "'total' => {$local}total"; - } - if (isset($namedAttr['iteration'])) { - $prop['iteration'] = "'iteration' => 0"; - } - if (isset($namedAttr['index'])) { - $prop['index'] = "'index' => -1"; - } - if (isset($namedAttr['show'])) { - $prop['show'] = "'show' => ({$local}total > 0)"; - } - if (!empty($namedAttr)) { - $_vars = 'array(' . join(', ', $prop) . ')'; - $output .= "{$foreachVar} = new Smarty_Variable({$_vars});\n"; - } + if (isset($itemAttr[ 'iteration' ])) { + $output .= "{$itemVar}->iteration = 0;\n"; } - if (isset($attributes['key'])) { - $output .= "\$_smarty_tpl->tpl_vars['{$key}'] = new Smarty_Variable();\n"; + if (isset($itemAttr[ 'index' ])) { + $output .= "{$itemVar}->index = -1;\n"; } - if (isset($namedAttr['first']) || isset($itemAttr['first'])) { - $output .= "{$local}first = true;\n"; - } - if (isset($itemAttr['iteration'])) { - $output .= "{$itemVar}->iteration=0;\n"; - } - if (isset($itemAttr['index'])) { - $output .= "{$itemVar}->index=-1;\n"; - } - if ($needIteration) { - $output .= "{$local}iteration=0;\n"; - } - $output .= "{$itemVar}->_loop = false;\n"; $output .= "foreach (\$_from as {$keyTerm}{$itemVar}->value) {\n"; $output .= "{$itemVar}->_loop = true;\n"; - if (isset($attributes['key']) && isset($itemAttr['key'])) { + if (isset($attributes[ 'key' ]) && isset($itemAttr[ 'key' ])) { $output .= "\$_smarty_tpl->tpl_vars['{$key}']->value = {$itemVar}->key;\n"; } - if (isset($itemAttr['iteration'])) { + if (isset($itemAttr[ 'iteration' ])) { $output .= "{$itemVar}->iteration++;\n"; } - if (isset($itemAttr['index'])) { + if (isset($itemAttr[ 'index' ])) { $output .= "{$itemVar}->index++;\n"; } - if ($needIteration) { - $output .= "{$local}iteration++;\n"; + if (isset($itemAttr[ 'first' ])) { + $output .= "{$itemVar}->first = !{$itemVar}->index;\n"; } - if (isset($itemAttr['first'])) { - $output .= "{$itemVar}->first = {$local}first;\n"; - } - if (isset($itemAttr['last'])) { - $output .= "{$itemVar}->last = {$local}iteration == {$local}total;\n"; + if (isset($itemAttr[ 'last' ])) { + $output .= "{$itemVar}->last = {$itemVar}->iteration == {$itemVar}->total;\n"; } if ($this->isNamed) { - if (isset($namedAttr['iteration'])) { + if (isset($namedAttr[ 'iteration' ])) { $output .= "{$foreachVar}->value['iteration']++;\n"; } - if (isset($namedAttr['index'])) { + if (isset($namedAttr[ 'index' ])) { $output .= "{$foreachVar}->value['index']++;\n"; } - if (isset($namedAttr['first'])) { - $output .= "{$foreachVar}->value['first'] = {$local}first;\n"; + if (isset($namedAttr[ 'first' ])) { + $output .= "{$foreachVar}->value['first'] = !{$foreachVar}->value['index'];\n"; } - if (isset($namedAttr['last'])) { - $output .= "{$foreachVar}->value['last'] = {$local}iteration == {$local}total;\n"; + if (isset($namedAttr[ 'last' ])) { + $output .= "{$foreachVar}->value['last'] = {$foreachVar}->value['iteration'] == {$foreachVar}->value['total'];\n"; } } - if (isset($namedAttr['first']) || isset($itemAttr['first'])) { - $output .= "{$local}first = false;\n"; - } - $output .= "{$local}saved_local_item = {$itemVar};\n"; + $output .= "{$local}saved = {$itemVar};\n"; $output .= "?>"; return $output; @@ -294,10 +248,10 @@ class Smarty_Internal_Compile_Foreachelse extends Smarty_Internal_CompileBase // check and get attributes $_attr = $this->getAttributes($compiler, $args); - list($openTag, $nocache, $local, $restoreVars, $itemVar, $foo) = $this->closeTag($compiler, array('foreach')); - $this->openTag($compiler, 'foreachelse', array('foreachelse', $nocache, $local, $restoreVars, $itemVar, false)); + list($openTag, $nocache, $local, $itemVar, $foo) = $this->closeTag($compiler, array('foreach')); + $this->openTag($compiler, 'foreachelse', array('foreachelse', $nocache, $local, $itemVar, false)); $output = "_loop) {\n?>"; return $output; @@ -329,19 +283,16 @@ class Smarty_Internal_Compile_Foreachclose extends Smarty_Internal_CompileBase $compiler->tag_nocache = true; } - list($openTag, $compiler->nocache, $local, $restoreVars, $itemVar, $restore) = + list($openTag, $compiler->nocache, $local, $itemVar, $restore) = $this->closeTag($compiler, array('foreach', 'foreachelse')); $output = "smarty->ext->_foreach->restore(\$_smarty_tpl);\n"; $output .= "?>"; - return $output; } } diff --git a/libs/sysplugins/smarty_internal_runtime_foreach.php b/libs/sysplugins/smarty_internal_runtime_foreach.php index 689636ad..8e1bb91e 100644 --- a/libs/sysplugins/smarty_internal_runtime_foreach.php +++ b/libs/sysplugins/smarty_internal_runtime_foreach.php @@ -1,16 +1,100 @@ tpl_vars[ $item ])) { + $saveVars[ $item ] = $tpl->tpl_vars[ $item ]; + } + if ($key) { + if (isset($tpl->tpl_vars[ $key ])) { + $saveVars[ $key ] = $tpl->tpl_vars[ $key ]; + } + $tpl->tpl_vars[ $key ] = new Smarty_Variable(); + } + if (!is_array($from) && !is_object($from)) { + settype($from, 'array'); + } + $total = $needTotal ? $this->count($from) : 1; + $tpl->tpl_vars[ $item ] = new Smarty_Variable(); + if ($needTotal) { + $tpl->tpl_vars[ $item ]->total = $total; + } + $tpl->tpl_vars[ $item ]->_loop = false; + if ($name) { + $namedVar = "__smarty_foreach_{$name}"; + if (isset($tpl->tpl_vars[ $namedVar ])) { + $saveVars[ $namedVar ] = $tpl->tpl_vars[ $namedVar ]; + } + $namedProp = array(); + if (isset($properties[ 'total' ])) { + $namedProp[ 'total' ] = $total; + } + if (isset($properties[ 'iteration' ])) { + $namedProp[ 'iteration' ] = 0; + } + if (isset($properties[ 'index' ])) { + $namedProp[ 'index' ] = - 1; + } + if (isset($properties[ 'show' ])) { + $namedProp[ 'show' ] = ($total > 0); + } + $tpl->tpl_vars[ $namedVar ] = new Smarty_Variable($namedProp); + } + $this->stack[] = $saveVars; + + return $from; + } + + /** + * Restore saved variables + * + * @param \Smarty_Internal_Template $tpl + */ + public function restore(Smarty_Internal_Template $tpl) + { + foreach (array_pop($this->stack) as $k => $v) { + $tpl->tpl_vars[ $k ] = $v; + } + } + + /* + * * [util function] counts an array, arrayAccess/traversable or PDOStatement object * * @param mixed $value