PHP Iterator cannot be used with foreach by reference

I have an object that implements Iterator and contains 2 arrays: "records" and "pages". Whenever I scroll this object, I want to change the record array, but I get the error message An iterator cannot be used with foreach by reference , which, as I see, started in PHP 5.2 .

My question is: how can I use the Iterator class to change the value of a looped object when using foreach on it?

My code is:

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

The reason for this is that sometimes $flavors will not be an instance of my class and instead will just be a simple array. I want to be able to modify this array easily, regardless of its type.

+5
source share
3 answers

I just tried creating an iterator that used:

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

But that still didn't work.

The best I can recommend is to implement \ArrayAccess , which will allow you to do this:

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

Using generators:

An update based on Marks comments for generators, the following will allow you to iterate over the results without having to implement \Iterator or \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(); } 

This is a feature available in PHP 5.5.

+5
source

Extending the Flosculus solution, if you do not want to refer to a key every time you use an iterated variable, you can assign a link to it as a new variable in the first line of your foreach.

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

This is functionally identical to using the key on the base object, but it helps to keep the code in order, and the variable names are short ... If you do such things.

0
source

If you implemented iterator functions in your calss, I would suggest adding another method to the "setCurrent ()" class:

 //$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... } 

Then you can simply use this function inside the foreach loop:

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

If you need this function in other classes, you can also define a new iterator and extend the Iterator interface to contain setCurrent ()

0
source

All Articles