4

我收到了这个通知:

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

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

手册上说的是关于 ArrayIterator

此迭代器允许在迭代数组和对象时取消设置和修改值和键。

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

版本: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 
            }
        }
    }
}
?>
4

3 回答 3

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

迭代器正在迭代的底层 ArrayObject发生变异,因此如果您在同一个 Arrayobject 上同时有多个活动迭代器,您仍然会遇到相同的错误。

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

于 2013-01-10T21:50:25.450 回答
1

如果您从数组中删除最后一条记录,则下一个 foreach 循环可能会失败(内部调用 $this->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;

    }
于 2015-03-18T06:45:05.430 回答
0

这花了我这么长时间!我使用此页面上的配方(未成功)清除 ArrayObject 存储的内容,然后我发现了这个小笨蛋..

$this->exchangeArray(array());

魔法!

于 2016-12-29T19:41:26.673 回答