The for
performed mildly better about the foreach
, in this case because the function range
returns a array of elements resulting from iteration and accesses each item of this.
See a comparison between the two forms in a 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";
Upshot:
12345678910....
For => Tempo decorrido: 0.48403 segundos
1234567891011....
Foreach => Tempo decorrido: 0.74004 segundos
The result may be quite a lot different depending on the execution environment. Other ways to measure code performance in PHP can be seen in the question Measuring code performance in PHP?
Related question: To what extent premature optimization is a problem?
Alternative
Starting with PHP 5.5, support for Generators, the idea behind the generators is that a function does not return a unique value, but rather a sequence of values instead, where each value is issued one by one. In other words, generators allow to implement Iterators in a simpler way and without the complexity of implementing a class that implements the interface Iterator
.
An advantage to use generators is the possibility to iterate over a data set without putting them in memory at once, something that the function range()
does not. When the function generator is executed, is returned through the reserved word yield
(a kind of return
special), one key/value and, when requested the next element of the Iterator
, the function generator continues where the last one left off yield
.
Follow another comparative, now in a loop of 600000 iterations, and also comparing a function generator, the xrange
:
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 interfere little in performance, use the foreach
in situations where it is only necessary sweep to array, the for
, for situations where it is necessary to work with the index elements, for example, access previous or later elements in the current iteration. Already the Generators, use in situations where it is necessary to bypass memory limits.
Without even executing the code, I would say that the first fragment is faster, since you don’t need to create an array, or access its values.
– bfavaretto