In PHP we have the for
and foreach
loops, which are both handy, but there is
a case where a 3rd type of for loop would be handy: Iterators.
With 5.5 it became super easy to use Iterators, by simple creating a Generator. While
working on my itertools
port to PHP (here), I found a situation where both the for
and foreach
constructs fell short.
I had created counter
Generator which just creates an Iterator that starts at a given number and counts indefinitely. Then, I wanted to create a version of range
which used an Iterator. Now, I could do this with a few for
loops like in the PHP docs, but I wanted to use my new fancy counter
function, so I started with a for
loop:
<?php
for ($c = counter($start, $step); $c->current() <= $end; $c->next()) {
yield $c->current();
}
Pretty simple, but ugly. So I tried it with a foreach
loop:
<?php
foreach (counter($start, $step) as $i) {
yield $i;
if ($i === $end) {
break;
}
}
A little bit better, but could still be better.
After being annoyed by this, I had an idea for a new type of loop; the "foreach until" loop:
<?php
foreach (counter($start, $step) as $i) until ($i === $end) {
yield $i;
}
This could be useful in all sorts of situations. I know a lot of people may not want to add a new keyword to PHP, so there is an alternative as well.
Same thing as above, except it is "while n is true" instead of "until n is true":
<?php
foreach (counter($start, $step) as $i) while ($i !== $end) {
yield $i;
}
Thoughts?
The while
or until
checks should happen after the body of the foreach
has been executed. This will keep it in-line with the current do...while
loop construct.
We could also keep it more in-line with the do...while
construct and append the while
or until
expressions to the end of the loop:
<?php
foreach (counter($start, $step) as $i) {
yield $i;
} until ($i === $end);
and
<?php
foreach (counter($start, $step) as $i) {
yield $i;
} while ($i !== $end);
I do not prefer this syntax personally, but it is more consistent with the other loops.
Another Example
You could be looping over all the files in a directory and parsing them. If you wanted to allow something to interrupt it, you could add an
until (check_for_interrupt())
orwhile ( ! check_for_interrupt())
.