Page 1 of 1

foreach entry in php-manual incorrect???

Posted: Sat Aug 06, 2005 3:30 am
by tores
In the php-manual it's claimed that:
Note: Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. Therefore, the array pointer is not modified as with the each() construct, and changes to the array element returned are not reflected in the original array. However, the internal pointer of the original array is advanced with the processing of the array. Assuming the foreach loop runs to completion, the array's internal pointer will be at the end of the array.
Especially note the last two sentences.
In php 5.0.3 when the following code is executed

Code: Select all

$a = range('a', 'd');

echo 'key before: '.key($a).'<br \>';
foreach ($a as $idx => $value) {
	echo 'key='.key($a)." idx=$idx (value=$value)<br \>";
}
echo 'key after: '.key($a).'<br \>';
the following is printed,

Code: Select all

key before: 0
key=0 idx=0 (value=a)
key=0 idx=1 (value=b)
key=0 idx=2 (value=c)
key=0 idx=3 (value=d)
key after: 0
clearly contradicting the statement about the array internal pointer being advanced in the processing of the loop.

Posted: Sat Aug 06, 2005 5:52 am
by McGruff
This runs green (php4 not php5) and seems to back up the manual:

Code: Select all

class TestOfForeach extends UnitTestCase 
{
    function TestOfForeach() 
    {
        $this->UnitTestCase();
    }    
    function test() 
    {
        $array = array('foo'=>1, 'bar'=>2);
        $this->assertEqual(key($array), 'foo');
        foreach($array as $value) {}
        $this->assertIdentical(key($array), null);
        reset($array);
        $this->assertEqual(key($array), 'foo');
    }
}
I've been avoiding php5. It is supposed to be backward comaptible though so I'd be surprised if they've changed this behaviour. Can you run the test above (using SimpleTest)?

Posted: Sat Aug 06, 2005 6:18 am
by tores
Tried SimpleTest with the code-snippet posted by McGruff.
Here's what was printed
1/1 test cases complete: 3 passes, 0 fails and 0 exceptions.
So I guess everything is okey?
Haven't done any unit testing before. What exactly does this code-snippet do?

Posted: Sat Aug 06, 2005 6:37 am
by McGruff
It just documents how the internal array pointer is affected by a foreach loop.

An assertion is made that the pointer is aimed at the 'foo' key after creating the array. Next, that a foreach loop moves the pointer past the end of the array. Finally, that a reset call will move it back to the start.

Posted: Sat Aug 06, 2005 6:42 am
by tores
The code-snippet was easy once I got a close look at it :)

However further testing shows that the key function call is the culprit.

Now this works as expected:

Code: Select all

$a = range('a', 'd');
foreach ($a as $value) {
	// key($a);
}
echo (key($a) === null) ? 'this is right' : 'this is wrong';
This, however, doesn't

Code: Select all

$a = range('a', 'd');
foreach ($a as $value) {
	key($a);
}
echo (key($a) === null) ? 'this is right' : 'this is wrong';
So I guess calling key inside foreach resets the internal array pointer...
This fails in php5 at least:

Code: Select all

class TestOfForeach extends UnitTestCase
{
    function TestOfForeach()
    {
        $this->UnitTestCase();
    }    
    function test()
    {
        $array = array('foo'=>1, 'bar'=>2);
        $this->assertEqual(key($array), 'foo');
        foreach($array as $value) { key($array); }
        $this->assertIdentical(key($array), null);
        reset($array);
        $this->assertEqual(key($array), 'foo');
    }
}