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: 2021-04-13 11:54 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: cmb (profile)
Status: Closed Package: SPL related
PHP Version: Irrelevant OS: openSUSE 11.4/Debian 5
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: olav at fwt dot no
New email:
PHP Version: OS:

 

 [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...
 [2021-04-13 11:54 UTC] cmb@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: cmb
 [2021-04-13 11:54 UTC] cmb@php.net
Indeed, fixed as of PHP 7.0.0.
 [2021-04-13 11:54 UTC] cmb@php.net
Indeed, fixed as of PHP 7.0.0.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 13:01:29 2024 UTC