Are multiple iterators possible in php?

PLEASE CHECK THE VOLKERK ANSWERS too, it provided a different solution, but I can not mark two messages as an answer :(


Good afternoon!

I know that C # allows you to use multiple iterators using yield, as described here: Is it possible to have multiple iterators in C #?

PHP has an iterator interface. Is it possible to implement more than one iteration script for a class?

Details (EDIT):

For example, I have a TreeNode class that implements a single node tree. An entire tree can be expressed in only one class. I want to provide iterators for iterating all the direct and indirect children of the current node, for example using BreadthFirst or DepthFirst order.

I can implement these iterators as separate classes, but at the same time I need the node tree to expand it as public.

C # pseudo code:

public class TreeNode<T> { ... public IEnumerable<T> DepthFirstEnumerator { get { // Some tree traversal using 'yield return' } } public IEnumerable<T> BreadthFirstEnumerator { get { // Some tree traversal using 'yield return' } } } 
+4
source share
4 answers

Yes, you can.

 foreach(new IteratorOne($obj) as $foo) .... foreach(new IteratorTwo($obj) as $bar) ..... 

Actually, as long as you implement the Iterator class, you can apply any arbitrary IteratorIterator to it. This is a good thing, because application metarators are not required to know anything about the class in question.

Consider, for example, an iterable class like this

 class JustList implements Iterator { function __construct() { $this->items = func_get_args(); } function rewind() { return reset($this->items); } function current() { return current($this->items); } function key() { return key($this->items); } function next() { return next($this->items); } function valid() { return key($this->items) !== null; } } 

Let us define some metarator

 class OddIterator extends FilterIterator { function accept() { return parent::current() % 2; } } class EvenIterator extends FilterIterator { function accept() { return parent::current() % 2 == 0; } } 

Now apply the metatherators to the base class:

  $list = new JustList(1, 2, 3, 4, 5, 6, 7, 8, 9); foreach(new OddIterator($list) as $p) echo $p; // prints 13579 foreach(new EvenIterator($list) as $p) echo $p; // prints 2468 

UPDATE: php has no inner classes, so you are out of luck here without resorting to eval, at least. Your iterators should be separate classes that are aware of the structure of the base layer. You can make this less harmful by providing methods in the base class that instantiate iterators behind the scenes:

  class TreeDepthFirstIterator implements Iterator { function __construct($someTree)..... } class Tree { function depthFirst() { return new TreeDepthFirstIterator($this); } .... } foreach($myTree->depthFirst() as $node)..... 

Another option is to use lambdas instead of foreach. This is better and more flexible, but requires php5.3:

  class Tree { function depthFirst($func) { while($node = .....) $func($node); ..... $myTree->depthFirst(function($node) { echo $node->name; }); 
+5
source

This code shows how to add multiple iterators to a class.

 class TreeNode { public function getOddIterator () { return new OddIterator($this->nodes); } public function getEvenIterator () { return new EvenIterator($this->nodes); } } 
+1
source

For your purpose, it may be enough that your class has a β€œmode” flag, so the user can choose whether there is a first or first depth iterator.

 class Tree { const TREE_DEPTH_FIRST = 0; const TREE_BREADTH_FIRST = 0; protected $mode; protected $current; public function __construct($mode=Tree::TREE_DEPTH_FIRST) { $this->mode = $mode; } public function setMode($mode) { ... } public function next() { $this->current = advance($this->current, $this->mode); } .... } 

(and a short answer to your initial question: php does not have syntactic yield return syntax, and it does not have internal private classes, that is, regardless of what you need the iterator you are returning with, the "original" object should be exposed to the outside world Thus, you are likely to finish β€œpreparing” all the elements for an iterator object such as an ArrayIterator, which is what you avoid using yield )

+1
source

You can have multiple iterators. The key idea in Iterator is to take responsibility for accessing and traversing the list object and putting it in the iterator object. Therefore, if you want to have several iterators with the same list or different lists; no problems.

Here you can find four different PHP examples:

http://www.php5dp.com/category/design-patterns/iterator/

You can also use them with linked lists.

Cheers, Bill

0
source

Source: https://habr.com/ru/post/1304060/


All Articles