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