php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #55157 ArrayIterator::offsetUnset(); does not work correctly
Submitted: 2011-07-07 06:52 UTC Modified: 2017-10-24 07:25 UTC
Votes:18
Avg. Score:4.4 ± 0.8
Reproduced:18 of 18 (100.0%)
Same Version:7 (38.9%)
Same OS:8 (44.4%)
From: olav at fwt dot no Assigned:
Status: Open Package: SPL related
PHP Version: Irrelevant OS: openSUSE 11.4/Debian 5
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2011-07-07 06:52 UTC] olav at fwt dot no
Description:
------------
ArrayIterator always skips the second element in the array when calling 
offsetUnset(); on it while looping through.

Using the key from iterator and unsetting in the actual ArrayObject works as 
expected.

Running php 5.3.5 on openSUSE 11.4
Replicated same bug on Debian 5 running PHP 5.2.6-1+lenny9.

php5 is installed as binary on both systems, SPL is builtin package.


Test script:
---------------
<?php

// Create a array range from 0 to 9
$a = new ArrayObject( range( 0,9 ) );
$b = new ArrayIterator( $a );
 
for ( $b->rewind(); $b->valid(); $b->next() )
{
    echo "#{$b->current()} - \r\n";
    $b->offsetUnset( $b->key() );
}
?>

Expected result:
----------------
Expected a list of from 0 to 9 echoed out.

Actual result:
--------------
Lists out 0 and then 2-9 leaving index 1 untouched in the original ArrayObject.


Patches

Add a Patch

Pull Requests

Pull requests:

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2011-07-07 07:05 UTC] colder@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: colder
 [2011-07-07 07:17 UTC] joey@php.net
Just to narrow the scope of the bug a bit:

$a = range( 0,9 );
$b = new ArrayIterator( $a );
 
foreach($b as $k=>$v) {
    $b->offsetUnset($k);
}

var_dump($b->getArrayCopy()); // why is 1 still around?
 [2011-07-07 07:18 UTC] joey@php.net
Sorry, I should clarify that the code above gives:

array(1) { [1]=> int(1) }

Whereas you'd probably expect:

array(0) { }
 [2011-07-19 15:09 UTC] gergo at gergoerdosi dot com
I have the same problem, used this code:

$items = new ArrayObject(array(1, 2, 3, 4, 5));

foreach($items as $item) {
	if(in_array($item, array(2, 3, 4))) {
		$items->offsetUnset($item);
	}
}

var_dump($items->getArrayCopy());

Expected result: array(1, 5), actual result: array(1, 3, 5).
 [2011-07-19 15:18 UTC] gergo at gergoerdosi dot com
Please ignore my comment above. The offsetUnset() method unsets elements using 
their index. Changing the code to this gives the expected result (0, 4):

$items = new ArrayObject(array(0, 1, 2, 3, 4));

foreach($items->getArrayCopy() as $item) {
	if(in_array($item, array(1, 2, 3))) {
		$items->offsetUnset($item);
	}
}

var_dump($items->getArrayCopy());
 [2012-11-19 01:17 UTC] levim@php.net
It seems that calling `ArrayIterator::offsetUnset` moves the internal pointer to 
the next element when removing the first index:

$a = range( 0,3 );
$b = new ArrayIterator( $a );

for ($b->rewind(); $b->valid(); ) {
    echo "{$b->key()} => {$b->current()}\n";
    $b->offsetUnset($b->key());
}

var_dump($b->getArrayCopy());
 [2014-08-29 06:46 UTC] jan dot kahoun at heureka dot cz
I have the same problem, are you planning to fix it?
 [2015-04-19 00:47 UTC] mw dot wanrooij at vodafonevast dot nl
Same problem here, as mentioned earlier: "It seems that calling `ArrayIterator::offsetUnset` moves the internal pointer to 
the next element when removing the first index"

Is there any progress on a fix?
 [2017-10-24 07:25 UTC] kalle@php.net
-Status: Assigned +Status: Open -Assigned To: colder +Assigned To:
 [2020-04-22 07:24 UTC] alexinbeijing at gmail dot com
This bug is already fixed and the report should be closed.

The original repro code prints keys 0, 2, 4, 6, and 8, which is expected. This is because when ::offsetUnset() deletes the current iteration key, it bumps the current iteration position to the next element. Then, when ::next() is called, it bumps the position forward again. So it results in iterating over every second element.

The subsequent repro code which was stated to only leave key 1 in place actually leaves all the odd-numbered keys (1, 3, 5, 7, and 9) in place, for the same reason stated above.

Just seeing if documentation for ::offsetUnset() can be updated to make this clearer...
 [2020-06-09 09:32 UTC] alexinbeijing at gmail dot com
The following pull request has been associated:

Patch Name: Add note on behavior of ArrayIterator::offsetUnset when used on current iteration index
On GitHub:  https://github.com/php/doc-en/pull/118
Patch:      https://github.com/php/doc-en/pull/118.patch
 [2020-06-09 09:33 UTC] alexinbeijing at gmail dot com
Just submitted a PR to update the documentation on this issue...
 
PHP Copyright © 2001-2020 The PHP Group
All rights reserved.
Last updated: Thu Oct 22 16:01:24 2020 UTC