Atural
Atural

Reputation: 5439

ArrayObject::offsetUnset advances the internal pointer in an unexpected way

Hey guys i've the following scenario

$col = new ArrayObject();

for ($i = 0; $i < 5; $i++)
{
    $objItem = new stdClass;
    $objItem->someVar = $i;
    $col->append($objItem);
}

Now i want to remove some key via offsetUnset and did the following

foreach($col AS $key => $objItem)
{
    if ($key == 2)
    {
        $col->offsetUnset($key);
    }
    echo $key.'\n';
}

The funpart now is the unexpected output

0
1
2
4

For a better illustration - if you put a continue in like

foreach($col AS $key => $objItem)
{
    if ($key == 2)
    {
        $col->offsetUnset($key);
        continue;
    }
    echo $key.'\n';
}

the output is

0
1
4

I never ever would've thought it bypasses the key number 3 in this ArrayObject just because i removed the previous item - it looks like the internal pointer was incremented twice or something like that...

Keep in mind i also tried something like

$it = $col->getIterator();

foreach($it AS $key => $objItem)
{
    if ($key == 2)
    {
        $col->offsetUnset($key);
    }
    echo $key."\n";
}

the output is the same

Question:

Is this a normal behavior or do i overlook something crucial here?

pS: As nigel Ren pointed out this as a possible duplicate of Php, Spl, ArrayIterator, i've to point out i was looking here for an ArrayObject solution and didn't found any (i now know the ArrayIterator problem is probably the same) - but i would've never guessed that those are related to each other - in this respect i plead for not closing this question because it might help others too

Upvotes: 2

Views: 123

Answers (2)

Atural
Atural

Reputation: 5439

The solution for this Bug is actually pretty simple and was posted here by a user called Tsounabe.

I'm putting here his solution - only with one change - he was referring to an ArrayIterator and i was talking about an ArrayObject - but both are using the same function getArrayCopy

foreach($col->getArrayCopy() AS $key => $objItem)
{
    if ($key == 2)
    {
        $col->offsetUnset($key);
        continue;
    }
    echo $key.'\n';
}

Conclusion

The only satisfying solution here in order to avoid this bug is the use of getArrayCopy() which is documented on the official PHP Site under https://secure.php.net/manual/de/arrayobject.getarraycopy.php

Upvotes: 1

Niklesh Raut
Niklesh Raut

Reputation: 34914

In your code it is resetting object key after $col->offsetUnset($key); and continue with next key 3 after resetting it would the element whose ->someVar value is 4, that's why you get this output.

So you can simply use another iteration to print your object. it would work.

Live demo

Out put

0
1
3
4

Upvotes: 0

Related Questions