在迭代它时,ArrayObject不允许我取消设置值

enr*_*rey 4 php spl arrayobject

我收到了这个通知:

ArrayIterator :: next():数组在对象外被修改,内部位置在/ var/www中不再有效...

这是由foreach循环开始时由此代码生成的.与通知一起,foreach循环开始重复迭代.换句话说,只要发生这种情况,就会重置内部位置.但根据php手册,ArrayObject默认使用ArrayIterator.

手册说这是关于ArrayIterator的

这个迭代器允许在迭代Arrays和Objects时取消设置和修改值和键.

我在这里错过了什么吗?我发现了一些关于ArratIterator的bug报告,但不是这种.这是一个错误还是我的坏?

版本:PHP版本5.3.10-1ubuntu3.4

<?php
//file 1:
// no namespace
abstract class holder extends \ArrayObject{
    // abstract function init();

    public function __construct($init){
        parent::__construct($init, 1);
    }
}?>

<?php
//file 2:
namespace troops;
class holder extends \holder{
    public function __construct(){
        parent::__construct($this->init());
    }

    private function init(){
        return array( /*... some data from db ...*/ );
    }

    public function saveData(){
        foreach($this as $k  => $v){
            $this->save($v);
            if($v->number_of_items==0) {
                unset($k);
                // $this->offsetUnset($k); // tryed both 
            }
        }
    }
}
?>
Run Code Online (Sandbox Code Playgroud)

goa*_*oat 8

ArrayObject实现了IteratorAggregate,这意味着它有一个名为getIterator()的方法,它返回一个迭代器.

php的foreach循环将通过调用getIterator()方法自动检索迭代器,以便检索迭代器迭代.这很方便,但是你需要获得对这个迭代器的引用,以便在迭代器本身上调用offsetUnset()方法.这里的关键是你必须调用迭代器 offsetUnset()方法,而不是ArrayObjects offsetUnset()方法.

$ao = new ArrayObject();
$ao[] = 9;
$iter = $ao->getIterator();

foreach ($iter as $k => $v) 
    $iter->offsetUnset($k); // no error
Run Code Online (Sandbox Code Playgroud)

迭代器迭代的底层ArrayObject 被突变,因此如果同一个Arrayobject上同时有多个活动迭代器,您仍会遇到相同的错误.

这样做的理由很可能是迭代器可以节省内存而不必复制底层的ArrayObject,因为复制是处理添加内容时决定当前迭代器位置应该是什么的复杂性的唯一简单解决方案.或从底层数组中删除.