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

PHP迭代器不能通过引用与foreach一起使用,php,arrays,foreach,Php,Arrays,Foreach,我有一个实现迭代器的对象,它包含两个数组:“条目”和“页面”。每当我循环遍历这个对象时,我都想修改entries数组,但是我得到了一个错误迭代器不能用于foreach by reference,我在中看到了这个错误 我的问题是,在对循环对象使用foreach时,如何使用Iterator类来更改循环对象的值 我的代码: //$flavors = instance of this class: class PaginatedResultSet implements \Iterator { p

我有一个实现迭代器的对象,它包含两个数组:“条目”和“页面”。每当我循环遍历这个对象时,我都想修改entries数组,但是我得到了一个错误
迭代器不能用于foreach by reference
,我在中看到了这个错误

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

我的代码:

//$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();
}
使用生成器:

根据生成器上的标记注释进行更新,以下内容将允许您迭代结果,而无需实现
\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();
}

这是PHP5.5中提供的一个功能。

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

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

这在功能上与在基本对象上使用键相同,但有助于保持代码整洁,并缩短变量名。。。如果您在Cals中实现了迭代器函数,我建议您在类“setCurrent()”中添加另一个方法:

然后您可以在foreach循环中使用此函数:

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

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

为什么不先检查它是类还是数组,然后适当地处理它?@MuppetGrinder因为我在很多地方使用这些方法,我不想每次都要进行检查,也可以“通过引用”访问生成器的元素,因此这可能是一种替代方法。我最终实现了\ArrayAccess和\Iterator,然后使用$key=>$val样式而不是通过引用。这工作得很好。@MarkBaker我仍然需要研究它们是如何工作的,当它们说函数的状态在每次调用时都不会改变时,我对它们的意思有点困惑。@Flosculus-这意味着在对生成器进行迭代时,生成器中的变量不会超出范围,只有在它终止时才会超出范围(不再有效)…我目前正在写一本关于发电机的书PHP@MarkBaker对发电机进行了更新。谢谢,很有教育意义。
foreach ($flavors as $flavor) {
    $newFlavor = makeNewFlavorFromOldOne($flavor)
    $flavors -> setCurrent($newFlavor);
}