我有一个实现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
将不成为我班级的一个实例,而只是一个简单的数组。我希望能够轻松修改此数组,无论其类型如何。
答案 0 :(得分:5)
我刚尝试创建一个使用了:
的迭代器public function ¤t() {
$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()