2015-04-22 50 views
5

我有一個實現Iterator並擁有2個數組的對象:「entries」和「pages」。每當我循環訪問這個對象時,我想修改這個entries數組,但是我得到了錯誤An iterator cannot be used with foreach by reference,我在PHP 5.2中看到了這個錯誤。PHP迭代器不能與foreach一起使用引用

我的問題是,我如何使用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

爲什麼不檢查它是否是一個類Ø先數組,然後適當地對待它? – MuppetGrinder

+0

@MuppetGrinder因爲我在很多地方使用這些方法,所以我不想每次都檢查,而只是在一個地方。 – shiznatix

回答

5

我只是想創建其使用的迭代器:

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(); 
} 

這是PHP 5.5中的一項功能。

+0

也可以通過引用訪問Generator的元素,這樣可能是一種替代方法 –

+0

我最終實現了\ ArrayAccess和\ Iterator,然後使用$ key => $ val樣式而不是通過引用。這工作完美。 – shiznatix

+0

@MarkBaker我仍然需要研究這些工作是如何工作的,當他們說每次調用函數的狀態不會改變時,我對他們的意思有點困惑。 – Flosculus

0

在Flosculus的解決方案中進行擴展時,如果每次使用迭代變量時都不想引用該鍵,則可以在其foreach的第一行中爲其指定一個新變量。

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

這是功能上等同於使用基礎對象的關鍵,但有助於保持代碼整潔和變量名短......如果你到那種事。

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()

相關問題