foreach entry in php-manual incorrect???

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
tores
Forum Contributor
Posts: 120
Joined: Fri Jun 18, 2004 3:04 am

foreach entry in php-manual incorrect???

Post 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.
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post 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)?
tores
Forum Contributor
Posts: 120
Joined: Fri Jun 18, 2004 3:04 am

Post 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?
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post 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.
tores
Forum Contributor
Posts: 120
Joined: Fri Jun 18, 2004 3:04 am

Post 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');
    }
}
Post Reply