PHP 迭代器不能通过引用与 foreach 一起使用



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

我的问题是,如何使用 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不会是我的类的实例,而只是一个简单的数组。我希望能够轻松修改此数组,无论它是什么类型。

我刚刚尝试创建一个迭代器,它使用:

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

但这仍然没有奏效。

我能推荐的最好的是你实现 ArrayAccess ,这将允许您这样做:

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

使用生成器:

根据生成器上的标记注释进行更新,以下内容将允许您迭代结果,而无需实现IteratorArrayAccess

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 中提供的一项功能。

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

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

这在功能上与在基对象上使用键相同,但有助于保持代码整洁,变量名称简短... 如果你喜欢那种事情。

如果你在你的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);
}

如果你在其他类中需要这个函数,你也可以定义一个新的迭代器并扩展迭代器接口以包含 setCurrent()

最新更新