for
has a slightly better performance slightly the foreach
, in this case because function range
returns an array of elements resulting from the iteration and accesses each item from it.
See a comparison between the two forms in loop of 350000 iterations:
function bench($func) {
$tempo = -microtime(true);
$func();
$tempo += microtime(true);
return number_format($tempo, 4);
}
function func1() {
for($x = 1; $x < 350000; $x++) echo $x;
}
function func2() {
foreach(range(1, 350000) as $x) echo $x;
}
$tempoDecorrido = bench('func1');
echo "\n For => Tempo decorrido: {$tempoDecorrido} segundos \n";
$tempoDecorrido = bench('func2');
echo "\n Foreach => Tempo decorrido: {$tempoDecorrido} segundos \n";
Result:
12345678910....
For => Tempo decorrido: 0.48403 segundos
1234567891011....
Foreach => Tempo decorrido: 0.74004 segundos
The result may be quite different depending on the execution environment. Other ways to measure code performance in PHP can be seen in the How to measure code performance in PHP?
Related question: How early is optimization a problem?
Alternative
As of PHP 5.5, support for Generators in a simpler way and without the complexity of implementing a class that implements the Iterator
interface.
One advantage of using generators is the ability to iterate over a data set without putting them in memory at once , something that range()
function does not. When the generator function is executed, it is returned through the reserved word #), a key / value and when prompted for the next element of yield
the generator function continues from where the last return
stopped.
Here is another comparison, now in a loop of 600000 iterations, and also comparing a generator function, Iterator
:
function bench($func){
$tempo = -microtime(true);
echo $func();
$tempo += microtime(true);
return number_format($tempo, 4);
}
function xrange($inicio, $fim, $passo = 1) {
for ($i = $inicio; $i <= $fim; $i += $passo) yield $i;
}
function func1(){
for($x = 1; $x < 600000; $x++) echo $x;
}
function func2(){
foreach(xrange(1, 600000) as $x) echo $x;
}
function func3(){
foreach(range(1, 600000) as $x) echo $x;
}
$tempo = bench('func1');
echo "\n For: {$tempo} \n";
$tempo = bench('func2');
echo "\n xrange: {$tempo} \n";
$tempo = bench('func3');
echo "\n range: {$tempo} \n";
The result was:
1234567891011121314151...
For: 1.0861
123456789101112131415161...
xrange: 2.5801
12345678910111213141516171...
range: 2.7602
Using one or the other will not interfere with performance, use yield
on situations where it is only necessary to scan array , the xrange
, for situations where you need to work with index elements, for example, accessing previous or later elements in the current iteration. Already the Generators , use in situations where you need to circumvent the memory limits .