function process($tpl, &$textElements, $functionName, $functionChildren, $functionParameters, $functionPlacement, $rootNamespace, $currentNamespace)
 {
     /*
     {foreach <array> as [$keyVar =>] $itemVar
              [sequence <array> as $sequenceVar]
              [offset <offset>]
              [max <max>]
              [reverse]
     }
     */
     //eZDebug::writeDebug( $functionParameters, '$functionParameters' );
     $loop = new eZTemplateLoop(eZTemplateForeachFunction::FUNCTION_NAME, $functionParameters, $functionChildren, $functionPlacement, $tpl, $textElements, $rootNamespace, $currentNamespace);
     if (!$loop->initialized()) {
         return;
     }
     $loop->parseParamValue('array', $array);
     if (!is_array($array)) {
         $tpl->error(eZTemplateForeachFunction::FUNCTION_NAME, "Missing/malformed array to iterate through.", $functionPlacement);
         return;
     }
     $loop->parseParamVarName('item_var', $itemVarName);
     if (!$itemVarName) {
         $tpl->error(eZTemplateForeachFunction::FUNCTION_NAME, "Missing/malformed item variable name.", $functionPlacement);
         return;
     }
     $loop->parseParamVarName('key_var', $keyVarName);
     $loop->parseParamValue('max', $max);
     $loop->parseParamValue('offset', $offset);
     $loop->parseParamValue('reverse', $reverse);
     /*
      * run the loop itself
      */
     /*
         $offset and $max parameters must meet the following requirements:
          -  $offset + $max <= $nItems
          -  $offset >= 0
          -  $max    >= 0
         Otherwise they are not considered.
     */
     $arrayKeys = array_keys($array);
     $nItems = count($arrayKeys);
     $nItemsProcessed = 0;
     // do nothing in case of empty array
     if (!$nItems) {
         return;
     }
     // fix definitely incorrect offset
     if ($offset === null) {
         $offset = 0;
     } elseif ($offset < 0 || $offset >= $nItems) {
         if ($nItems || $offset < 0) {
             $tpl->warning(eZTemplateForeachFunction::FUNCTION_NAME, "Invalid 'offset' parameter specified.", $functionPlacement);
         }
         $offset = $offset < 0 ? 0 : $nItems;
     }
     // fix definitely incorrect max
     if ($max === null) {
         $max = $nItems - $offset;
     } elseif ($max < 0 || $offset + $max > $nItems) {
         if ($max < 0) {
             $tpl->warning(eZTemplateForeachFunction::FUNCTION_NAME, "Invalid 'max' parameter specified.", $functionPlacement);
         }
         $max = $nItems - $offset;
     }
     // process 'reverse' parameter
     if ($reverse === null) {
         $reverse = false;
     }
     if ($reverse) {
         $firstVal = $nItems - 1 - $offset;
         $lastVal = 0;
     } else {
         $firstVal = $offset;
         $lastVal = $nItems - 1;
     }
     if ($firstVal < $lastVal) {
         if ($keyVarName && !$tpl->hasVariable($keyVarName, $rootNamespace)) {
             $loop->initLoopVariable($keyVarName);
         }
         if (!$tpl->hasVariable($itemVarName, $rootNamespace)) {
             $loop->initLoopVariable($itemVarName);
         }
     }
     for ($i = $firstVal; $nItemsProcessed < $max && ($reverse ? $i >= $lastVal : $i <= $lastVal);) {
         $key =& $arrayKeys[$i];
         $val =& $array[$key];
         if ($keyVarName) {
             $tpl->setVariable($keyVarName, $key, $rootNamespace);
         }
         $tpl->setVariable($itemVarName, $val, $rootNamespace);
         $loop->setSequenceVar();
         // set sequence variable (if specified)
         $loop->processDelimiter($i);
         $loop->resetIteration();
         // process loop body
         if ($loop->processChildren()) {
             break;
         }
         // increment loop counter here for delimiter to be processed correctly
         $reverse ? $i-- : $i++;
         $loop->incrementSequence();
         $nItemsProcessed++;
     }
     $loop->cleanup();
 }
 function process($tpl, &$textElements, $functionName, $functionChildren, $functionParameters, $functionPlacement, $rootNamespace, $currentNamespace)
 {
     /*
      * Check function parameters
      */
     $loop = new eZTemplateLoop(eZTemplateForFunction::FUNCTION_NAME, $functionParameters, $functionChildren, $functionPlacement, $tpl, $textElements, $rootNamespace, $currentNamespace);
     if (!$loop->initialized()) {
         return;
     }
     $loop->parseScalarParamValue('first_val', $firstVal, $firstValIsProxy);
     $loop->parseScalarParamValue('last_val', $lastVal, $lastValIsProxy);
     if ($firstValIsProxy || $lastValIsProxy) {
         $tpl->error(eZTemplateForFunction::FUNCTION_NAME, "Proxy objects ({section} loop iterators) cannot be used to specify the range \n" . "(this will lead to indefinite loops in compiled mode).\n" . "Please explicitly dereference the proxy object like this: \$current_node.item.");
         return;
     }
     $loop->parseParamVarName('loop_var', $loopVarName);
     if ($firstVal === null || $lastVal === null || !$loopVarName) {
         $tpl->error(eZTemplateForFunction::FUNCTION_NAME, "Wrong arguments passed.");
         return;
     }
     if (!is_numeric($firstVal) || !is_numeric($lastVal)) {
         $tpl->error(eZTemplateForFunction::FUNCTION_NAME, "Both 'from' and 'to' values can only be numeric.");
         return;
     }
     $loop->initLoopVariable($loopVarName);
     /*
      * Everything is ok, run the 'for' loop itself
      */
     for ($i = $firstVal; $firstVal < $lastVal ? $i <= $lastVal : $i >= $lastVal;) {
         // set loop variable
         $tpl->setVariable($loopVarName, $i, $rootNamespace);
         $loop->setSequenceVar();
         // set sequence variable (if specified)
         $loop->processDelimiter();
         $loop->resetIteration();
         if ($loop->processChildren()) {
             break;
         }
         // increment loop variable here for delimiter to be processed correctly
         $firstVal < $lastVal ? $i++ : $i--;
         $loop->incrementSequence();
     }
     // for
     $loop->cleanup();
 }