PHP迭代器不能与foreach

时间:2015-04-22 13:08:51

标签: php arrays foreach

我有一个实现Iterator并保存2个数组的对象:"条目"和"页面"。每当我遍历这个对象时,我想修改条目数组,但是我得到了PHP 5.2中出现的错误An iterator cannot be used with foreach by reference

我的问题是,如何在使用Iterator时使用foreach类来更改循环对象的值?

我的代码:

//$flavors = instance of this class:
class PaginatedResultSet implements \Iterator {
    private $position = 0;

    public $entries = array();
    public $pages = array();

    //...Iterator methods...
}

//looping
//throws error here
foreach ($flavors as &$flavor) {
    $flavor = $flavor->stdClassForApi();
}

原因是有时候$flavors成为我班级的一个实例,而只是一个简单的数组。我希望能够轻松修改此数组,无论其类型如何。

3 个答案:

答案 0 :(得分:5)

我刚尝试创建一个使用了:

的迭代器
public function &current() {
    $element = &$this->array[$this->position];
    return $element;
}

但那仍然无效。

我可以推荐的最好的是你实施\ArrayAccess,这将允许你这样做:

foreach ($flavors as $key => $flavor) {
    $flavors[$key] = $flavor->stdClassForApi();
}

使用生成器:

根据Marks对生成器的评论进行更新,以下内容允许您迭代结果而无需实现\Iterator\ArrayAccess

class PaginatedResultSet {
    public $entries = array();

    public function &iterate()
    {
        foreach ($this->entries as &$v) {
            yield $v;
        }
    }
}

$flavors = new PaginatedResultSet(/* args */);

foreach ($flavors->iterate() as &$flavor) {
    $flavor = $flavor->stdClassForApi();
}

这是PHP 5.5中提供的功能。

答案 1 :(得分:0)

扩展Flosculus的解决方案,如果您不想在每次使用迭代变量时引用该键,您可以将其引用分配给foreach第一行中的新变量。

foreach ($flavors as $key => $f) {
  $flavor = &$flavors[$key];
  $flavor = $flavor->stdClassForApi();
}

这在功能上与在基础对象上使用键相同,但有助于保持代码整洁,变量名称简短......如果您遇到这种情况。

答案 2 :(得分:0)

如果你在calss中实现了迭代器函数,我建议在类“setCurrent()”中添加另一个方法:

//$flavors = instance of this class:
class PaginatedResultSet implements \Iterator {
    private $position = 0;

    public $entries = array();
    public $pages = array();

    /* --- Iterator methods block --- */
    private $current;

    public function setCurrent($value){
        $this->current = $value;
    }

    public function current(){
        return $this->current;
    }
    //...Other Iterator methods...
}

然后你可以在foreach循环中使用这个函数:

foreach ($flavors as $flavor) {
    $newFlavor = makeNewFlavorFromOldOne($flavor)
    $flavors -> setCurrent($newFlavor);
}

如果在其他类中需要此函数,还可以定义新的迭代器并扩展Iterator接口以包含setCurrent()