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

时间:2013-01-04 05:45:10

标签: 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 
            }
        }
    }
}
?>

3 个答案:

答案 0 :(得分:8)

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

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

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

foreach ($iter as $k => $v) 
    $iter->offsetUnset($k); // no error

迭代器在上迭代的底层ArrayObject将被变异,所以如果同一个Arrayobject上同时有多个活动迭代器,你仍然会遇到同样的错误。

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

答案 1 :(得分:1)

如果您从阵列中删除最后一条记录而不是下一个foreach循环可能会失败(internaly调用$ this-&gt; next()) 例如,当我有一个项目的数组,我将取消它,而不是下一个foreach失败。

所以它帮助我测试了有效性并在这种情况下打破了下一个循环。

deleteOffset = true;

foreach ($iterator as $key => $value)
    {
            if ($deleteOffset && $iterator->offsetExists($key) ) 
            {
                 $iterator->offsetUnset($key);                                       
            }                

        //if remove last record than the foreach ( $this->next() ) fails so 
        //we have to break in this case the next ->next call
        //after any ->offsetUnset calls

        if (!$iterator->valid()) break;

    }

答案 2 :(得分:0)

这花了我这么久!我使用这个页面上的配方(不成功)清除了ArrayObject存储的内容,然后我发现这个小伙伴......

$this->exchangeArray(array());

魔法!