我有一个实现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 ¤t() {
$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();
}
这是 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()