PHP5 Iterators + foreach

[email protected] (Robert Amos)
Newsgroups php.smarty.dev
Message-ID <[email protected]>
Hi all,

after the discussions in the IRC channel over the past few days about
adding support for iterators to foreach, I worked up the following
patch that adds almost complete support for it except for a few
specific problems.

When you're using foreach properties (like foreach.name.iteration,
etc) the last and total properties wont work. This is mostly because
you can't use count() on an iterator. This was discussed on the
php-dev list a few months back but nothing seems to have become of
that.

So I submit this now, and hopefully one of the other "smarties" might
have a brainwave and find a solution that doesn't involve looping over
the iterator twice. And testing with php4 would be nice also :)

For my test cases you can see:
<http://smarty.lexx.odynia.org/foreach.php> (please no flattening my
modem)

Special thanks must go to mensi firstly, for requesting this and doing
most of the thinking, and messju for his input ;)

-bok

Patch count be found below, and here:
<http://smarty.lexx.odynia.org/Smarty_Compiler.class.php.diff>

Index: Smarty_Compiler.class.php
===================================================================
RCS file: /repository/smarty/libs/Smarty_Compiler.class.php,v
retrieving revision 1.329
diff -u -r1.329 Smarty_Compiler.class.php
--- libs/Smarty_Compiler.class.php   27 Jul 2004 17:59:35 -0000      1.329
+++ libs/Smarty_Compiler.class.php   31 Jul 2004 16:26:27 -0000
@@ -1162,8 +1162,13 @@
         }

         if (isset($name)) {
-            $output .= "{$foreach_props}['total'] = count(\$_from =
(array)$from);\n";
-            $output .= "{$foreach_props}['show'] =
{$foreach_props}['total'] > 0;\n";
+            $output .= "if (function_exists('is_a') && is_a($from,
'IteratorAggregate')):\n";
+            $output .= "   {$foreach_props}['show'] =
{$from}->getIterator()->valid();\n";
+            $output .= "   \$_from = $from;\n";
+            $output .= "else:\n";
+            $output .= "   {$foreach_props}['total'] = count(\$_from
= (array)$from);\n";
+            $output .= "   {$foreach_props}['show'] =
{$foreach_props}['total'] > 0;\n";
+            $output .= "endif;\n";
             $output .= "if ({$foreach_props}['show']):\n";
             $output .= "{$foreach_props}['iteration'] = 0;\n";
             $output .= "    foreach (\$_from as
$key_part\$this->_tpl_vars['$item']):\n";
@@ -1171,7 +1176,16 @@
             $output .= "        {$foreach_props}['first'] =
({$foreach_props}['iteration'] == 1);\n";
             $output .= "        {$foreach_props}['last']  =
({$foreach_props}['iteration'] == {$foreach_props}['total']);\n";
         } else {
-            $output .= "if (count(\$_from = (array)$from)):\n";
+            $output .= "\$_show = false;\n";
+            $output .= "if (function_exists('is_a') && is_a($from,
'IteratorAggregate')):\n";
+            $output .= "    if ({$from}->getIterator()->valid()):\n";
+            $output .= "        \$_show = true;\n";
+            $output .= "    endif;\n";
+            $output .= "    \$_from = $from;\n";
+            $output .= "elseif (count(\$_from = (array)$from)):\n";
+            $output .= "    \$_show = true;\n";
+            $output .= "endif;\n";
+            $output .= "if (\$_show):\n";
             $output .= "    foreach (\$_from as
$key_part\$this->_tpl_vars['$item']):\n";
         }
         $output .= '?>';
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.