1--TEST--
2foreach with iteratorAggregate
3--FILE--
4<?php
5class EnglishMealIterator implements Iterator {
6    private $pos=0;
7    private $myContent=array("breakfast", "dinner", "tea");
8
9    public function valid(): bool {
10        global $indent;
11        echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
12        return $this->pos < count($this->myContent);
13    }
14
15    public function next(): void {
16        global $indent;
17        echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
18        $this->pos++;
19    }
20
21    public function rewind(): void {
22        global $indent;
23        echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
24        $this->pos=0;
25    }
26
27    public function current(): mixed {
28        global $indent;
29        echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
30        return $this->myContent[$this->pos];
31    }
32
33    public function key(): mixed {
34        global $indent;
35        echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
36        return "meal " . $this->pos;
37    }
38
39}
40
41class FrenchMealIterator implements Iterator {
42    private $pos=0;
43    private $myContent=array("petit dejeuner", "dejeuner", "gouter", "dinner");
44
45    public function valid(): bool {
46        global $indent;
47        echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
48        return $this->pos < count($this->myContent);
49    }
50
51    public function next(): void {
52        global $indent;
53        echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
54        $this->pos++;
55    }
56
57    public function rewind(): void {
58        global $indent;
59        echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
60        $this->pos=0;
61    }
62
63    public function current(): mixed {
64        global $indent;
65        echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
66        return $this->myContent[$this->pos];
67    }
68
69    public function key(): mixed {
70        global $indent;
71        echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
72        return "meal " . $this->pos;
73    }
74
75}
76
77
78Class EuropeanMeals implements IteratorAggregate {
79
80    private $storedEnglishMealIterator;
81    private $storedFrenchMealIterator;
82
83    public function __construct() {
84        $this->storedEnglishMealIterator = new EnglishMealIterator;
85        $this->storedFrenchMealIterator = new FrenchMealIterator;
86    }
87
88    public function getIterator(): Traversable {
89        global $indent;
90        echo "$indent--> " . __METHOD__  . "\n";
91
92        //Alternate between English and French meals
93        static $i = 0;
94        if ($i++%2 == 0) {
95            return $this->storedEnglishMealIterator;
96        } else {
97            return $this->storedFrenchMealIterator;
98        }
99    }
100
101}
102
103$f = new EuropeanMeals;
104var_dump($f);
105
106echo "-----( Simple iteration 1: )-----\n";
107foreach ($f as $k=>$v) {
108    echo "$k => $v\n";
109}
110echo "-----( Simple iteration 2: )-----\n";
111foreach ($f as $k=>$v) {
112    echo "$k => $v\n";
113}
114
115
116$indent = " ";
117echo "\n\n\n-----( Nested iteration: )-----\n";
118$count=1;
119foreach ($f as $k=>$v) {
120    echo "\nTop level "  .  $count++ . ": \n";
121    echo "$k => $v\n";
122    $indent = "     ";
123    foreach ($f as $k=>$v) {
124        echo "     $k => $v\n";
125    }
126    $indent = " ";
127}
128
129
130?>
131--EXPECTF--
132object(EuropeanMeals)#%d (2) {
133  ["storedEnglishMealIterator":"EuropeanMeals":private]=>
134  object(EnglishMealIterator)#%d (2) {
135    ["pos":"EnglishMealIterator":private]=>
136    int(0)
137    ["myContent":"EnglishMealIterator":private]=>
138    array(3) {
139      [0]=>
140      string(9) "breakfast"
141      [1]=>
142      string(6) "dinner"
143      [2]=>
144      string(3) "tea"
145    }
146  }
147  ["storedFrenchMealIterator":"EuropeanMeals":private]=>
148  object(FrenchMealIterator)#%d (2) {
149    ["pos":"FrenchMealIterator":private]=>
150    int(0)
151    ["myContent":"FrenchMealIterator":private]=>
152    array(4) {
153      [0]=>
154      string(14) "petit dejeuner"
155      [1]=>
156      string(8) "dejeuner"
157      [2]=>
158      string(6) "gouter"
159      [3]=>
160      string(6) "dinner"
161    }
162  }
163}
164-----( Simple iteration 1: )-----
165--> EuropeanMeals::getIterator
166--> EnglishMealIterator::rewind (0)
167--> EnglishMealIterator::valid (0)
168--> EnglishMealIterator::current (0)
169--> EnglishMealIterator::key (0)
170meal 0 => breakfast
171--> EnglishMealIterator::next (0)
172--> EnglishMealIterator::valid (1)
173--> EnglishMealIterator::current (1)
174--> EnglishMealIterator::key (1)
175meal 1 => dinner
176--> EnglishMealIterator::next (1)
177--> EnglishMealIterator::valid (2)
178--> EnglishMealIterator::current (2)
179--> EnglishMealIterator::key (2)
180meal 2 => tea
181--> EnglishMealIterator::next (2)
182--> EnglishMealIterator::valid (3)
183-----( Simple iteration 2: )-----
184--> EuropeanMeals::getIterator
185--> FrenchMealIterator::rewind (0)
186--> FrenchMealIterator::valid (0)
187--> FrenchMealIterator::current (0)
188--> FrenchMealIterator::key (0)
189meal 0 => petit dejeuner
190--> FrenchMealIterator::next (0)
191--> FrenchMealIterator::valid (1)
192--> FrenchMealIterator::current (1)
193--> FrenchMealIterator::key (1)
194meal 1 => dejeuner
195--> FrenchMealIterator::next (1)
196--> FrenchMealIterator::valid (2)
197--> FrenchMealIterator::current (2)
198--> FrenchMealIterator::key (2)
199meal 2 => gouter
200--> FrenchMealIterator::next (2)
201--> FrenchMealIterator::valid (3)
202--> FrenchMealIterator::current (3)
203--> FrenchMealIterator::key (3)
204meal 3 => dinner
205--> FrenchMealIterator::next (3)
206--> FrenchMealIterator::valid (4)
207
208
209
210-----( Nested iteration: )-----
211 --> EuropeanMeals::getIterator
212 --> EnglishMealIterator::rewind (3)
213 --> EnglishMealIterator::valid (0)
214 --> EnglishMealIterator::current (0)
215 --> EnglishMealIterator::key (0)
216
217Top level 1:
218meal 0 => breakfast
219     --> EuropeanMeals::getIterator
220     --> FrenchMealIterator::rewind (4)
221     --> FrenchMealIterator::valid (0)
222     --> FrenchMealIterator::current (0)
223     --> FrenchMealIterator::key (0)
224     meal 0 => petit dejeuner
225     --> FrenchMealIterator::next (0)
226     --> FrenchMealIterator::valid (1)
227     --> FrenchMealIterator::current (1)
228     --> FrenchMealIterator::key (1)
229     meal 1 => dejeuner
230     --> FrenchMealIterator::next (1)
231     --> FrenchMealIterator::valid (2)
232     --> FrenchMealIterator::current (2)
233     --> FrenchMealIterator::key (2)
234     meal 2 => gouter
235     --> FrenchMealIterator::next (2)
236     --> FrenchMealIterator::valid (3)
237     --> FrenchMealIterator::current (3)
238     --> FrenchMealIterator::key (3)
239     meal 3 => dinner
240     --> FrenchMealIterator::next (3)
241     --> FrenchMealIterator::valid (4)
242 --> EnglishMealIterator::next (0)
243 --> EnglishMealIterator::valid (1)
244 --> EnglishMealIterator::current (1)
245 --> EnglishMealIterator::key (1)
246
247Top level 2:
248meal 1 => dinner
249     --> EuropeanMeals::getIterator
250     --> EnglishMealIterator::rewind (1)
251     --> EnglishMealIterator::valid (0)
252     --> EnglishMealIterator::current (0)
253     --> EnglishMealIterator::key (0)
254     meal 0 => breakfast
255     --> EnglishMealIterator::next (0)
256     --> EnglishMealIterator::valid (1)
257     --> EnglishMealIterator::current (1)
258     --> EnglishMealIterator::key (1)
259     meal 1 => dinner
260     --> EnglishMealIterator::next (1)
261     --> EnglishMealIterator::valid (2)
262     --> EnglishMealIterator::current (2)
263     --> EnglishMealIterator::key (2)
264     meal 2 => tea
265     --> EnglishMealIterator::next (2)
266     --> EnglishMealIterator::valid (3)
267 --> EnglishMealIterator::next (3)
268 --> EnglishMealIterator::valid (4)
269