1

This is a strange question, but it's interesting so I thought I'd ask. Let's say I don't like how php's foreach loop operates and I always use it in the format, where all I did is added a counter outside and used it inside the foreach loop to tell if we're in the last element.

$counter = 1;
$array_size = count($array);
foreach($array as $item){
   //code
   if($counter == $array_size){ 
      $isLast = true 
   } else {
      $isLast = false; 
   }
   $counter++; 
}

My question is: can I override or fork or inherit (or whatever you want to call that) the original php foreach loop to include this new ability, so that I can now do this, without the need for initializing the counter and such.

newforeach($array as $item){
   //code
   $isLast = //something that returns true/false;
}

It's an interesting idea, so I wonder if one of the hardcore php guys here can somehow make this possible? or this sort of modification way too complicated without hacking the language itself?!

zmol
  • 2,834
  • 5
  • 26
  • 29
  • 2
    By definition, surely, changing the way a language control structure works requires "hacking the language itself" – Mark Baker Feb 09 '11 at 11:03
  • What about [your other question](http://stackoverflow.com/questions/4943719/in-foreach-islastitem-exists)? – Gumbo Feb 09 '11 at 11:07
  • 1
    To at least make it prettier you could do `$isLast = ($counter == $array_size);` – gnur Feb 09 '11 at 11:13
  • @Gumbo Not totally obsolete. The idea of modifying default structures is still kind of interesting. I won't need it for this one, but you never know, it might come in handy later. – zmol Feb 09 '11 at 11:24

5 Answers5

4

You could write a class that wraps the array you're iterating over (you'll need to have it implement the Iterator interface) with an isLast() method which performs this check for you.

Something like this (pseudocode):

$arrayIterator = new MyArrayIterator($myArray);

foreach ($arrayIterator as $item)
{
  if ($arrayIterator->isLast())
  {
    doStuff();
  }
}
Victor Welling
  • 1,867
  • 12
  • 14
  • 1
    [The CachingIterator has a `hasNext` method](http://stackoverflow.com/questions/4804599/adding-a-char-to-all-array-items-ap-art-from-last-using-for-foreach/4804812#4804812), so you can simply wrap the `ArrayIterator` into it. But +1 for suggesting Iterators. – Gordon Feb 09 '11 at 11:19
2

It seems a strange way to do things. Why not just have something like so:

$isLast = FALSE;
foreach( $array as $count => $item )
{
    $isLast = ($count+1 == count($array))
}

I'm sure someone else can clean that code up, it's been a while since I wrote PHP.

Alternatively, if you like your way of doing it, why not just put your if/then/else into a function say isLast, and call it like so:

$isLast = isLast($item, $array)

sevenseacat
  • 24,699
  • 6
  • 63
  • 88
  • 1
    There's a few solutions to zmol's problem in his previous question - http://stackoverflow.com/questions/4943719/in-foreach-islastitem-exists - your's won't work for associative arrays, or arrays where the key numbers aren't sequential (perhaps after a sort) and aren't missing any entries (no unsets or similar) – Mark Baker Feb 09 '11 at 11:08
  • @Mark Baker: Good point on the sequential keys. I assumed he wasn't working with an associative array, seeing as he didn't use the keys himself. And apologies for not seeing his previous question. – sevenseacat Feb 09 '11 at 11:09
  • no apologies necessary... I was just pointing you to a number of alternative solutions that don't all suffer from sequential-only syndrome – Mark Baker Feb 09 '11 at 11:12
2

If your question is simply "can you override the implementation of php's language constructs" the answer is no. This is a feature of other dynamic langauges like Javascript or Ruby often referred to as Monkey Patching or Duck Punching.

xzyfer
  • 13,937
  • 5
  • 35
  • 46
1

You could rewrite your foreach to a while loop and iterate through the items using next(), like so:

$array = array('a' => 'hi', 2 => 2515, 'as' => 'foo');
while (true) {
    $item = current($array);
    echo $item, "\n";
    if (!next($array)) {
        echo '^last item!';
        break;
    }
}
gnur
  • 4,671
  • 2
  • 20
  • 33
0

You could do it (without modifying the syntax):

function foreach_counter($ar, $callback) {
  $counter = 1;
  $array_size = count($ar);
  foreach($ar as $item){
    $callback($item, $counter, $counter == $array_size);
    $counter++; 
  }
}

foreach_counter(array('a','b'), function($item, $counter, $isLast) {
     echo $counter . ': ' . $item . '' . ($isLast ? 'END' : ',');
});
// outputs 1: a, 2: b END

However, as you can see, it becomes harder to read the succinct version, so although you can, you shouldn't do it - especially as long as you're just beginning to understand php.

Oftentimes, you want to build a string in such a loop. Use implode for that:

echo implode(', ', array(1,2,3));
// output: 1, 2, 3
phihag
  • 278,196
  • 72
  • 453
  • 469