views:

568

answers:

7

We have all heard of how in a for loop, we should do this:

<?php

for ($i = 0, $count = count($array); $i < $c; ++$i)
{
    // Do stuff while traversing array
}

?>

instead of this:

<?php

for ($i = 0; $i < count($array); ++$i)
{
    // Do stuff while traversing array
}

?>

for performance reasons (i.e. initializing $count would've called count() only once, instead of calling count() with every conditional check).

Does it then also make a difference if, in a foreach loop, I do this:

<?php

$array = do_something_that_returns_an_array();

foreach ($array as $key => $val)
{
    // Do stuff while traversing array
}

?>

instead of this:

<?php

foreach (do_something_that_returns_an_array() as $key => $val)
{
    // Do stuff while traversing array
}

?>

assuming circumstances allow me to use either? That is, does PHP call the function only once in both cases, or is it like for where the second case would call the function again and again?

+2  A: 

Yes - I'd say it would call that function everytime.

I would set up an example to see what happens. Something like

function do_something_that_returns_an_array() {
    echo 'I have been called!'; 
    return array('i am an', 'array');

}

If you see that echo'd twice, you know it's calling it everytime.

alex
+4  A: 

foreach makes a copy of the input array and works on that in each iteration. So you can use foreach (do_something_that_returns_an_array() as $key => $val) and it'll call do_something_that_returns_an_array() only once.

deceze
That wording is not quite correct. Technically PHP arrays are copy-on-write so when you say the array is copied, the wording is at best ambiguous and at worst misleading. The return value is simply used "as is".
cletus
A: 

$MatchingFiles is an array.

$fullPath stores a string with many paths.

foreach($matchingFiles as $IDX => $fullPath) {

}

RPK
What does this have to do with the question?
alex
What? I don't get it.
jensgram
I just illustrate the use of ForEach. Any mistake?
RPK
Not a mistake per se, but the question isn't about _how_ to use a `for` loop. It was about how it behaves in a very specific case.
jensgram
+8  A: 

foreach() is implemented using iterators - thus it only calls the function that returns an array once, and then uses the iterator which points to the existing result set to continue with each item.

Amber
A: 

foreach() works with Iterator or IteratorAggregate objects (e.g., arrays and objects implementing the interface). It can't work with immutable objects. Functions return immutable objects, so the returning array have to be copied into Iterator object before foreaching (it's made by php itself)

valya
Could you explain? I'm not sure of the difference between enumerable and immutable.
BoltClock
immutable == very constant :) you cant change the object which is returned by function in php, it can't be used by L-Value (f() = 1 fails, either, i think, will array_push(f(), 123) )
valya
Functions don't return immutable objects. Due to the particularities of object references, you can dereference the object and do `getObject()->foo = 'bar'` quite fine (and if there's a reference to the object, it gets updated)... You can't dereference arrays (`getArray()['foo']` doesn't work). But there is no such thing as an immutable object in PHP. You can always dereference or modify an object (access restrictions not withstanding).
ircmaxell
+1  A: 

I've always assumed that do_something_that_returns_an_array() only runs once because, unlike in the for loop, there's no reason for it to run multiple times. The reason the for loop truth checker runs at the end of every iteration is to allow for very complicated checkers.

As a test, I did the following:

function get_array() {echo 5; return array(1,2,3,4,5);}
foreach(get_array() as $key => $value) {}

The script printed 5 once. Therefore, the function get_array() only evaluates once.

Steven Xu
+2  A: 

I think testing it will surely answer that.

Here is my code:

<?php

function GetArray() {
    echo "I am called.\n";
    return array("One"=>1, "Two"=>2, "Three"=>3, "Four"=>4, "Five"=>5);
}

echo "Case #1\n";
$array = GetArray();
foreach ($array as $key => $val){
    // Do stuff while traversing array
    echo "    Inside the loop: $key => $val\n";
}
echo "\n";

echo "Case #2\n";
foreach (GetArray() as $key => $val) {
    // Do stuff while traversing array
    echo "    Inside the loop: $key => $val\n";
}
echo "\n";

and here is the result:


Case #1
I am called.
    Inside the loop: One => 1
    Inside the loop: Two => 2
    Inside the loop: Three => 3
    Inside the loop: Four => 4
    Inside the loop: Five => 5

Case #2
I am called.
    Inside the loop: One => 1
    Inside the loop: Two => 2
    Inside the loop: Three => 3
    Inside the loop: Four => 4
    Inside the loop: Five => 5

They both read call function once. So no different.

NawaMan