--- /dev/null
+--TEST--
+foreach with Iterator.
+--FILE--
+<?php
+
+class MealIterator implements Iterator {
+ private $pos=0;
+ private $myContent=array("breakfast", "lunch", "dinner");
+
+ public function valid() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ return $this->pos<3;
+ }
+
+ public function next() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ return $this->myContent[$this->pos++];
+ }
+
+ public function rewind() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ $this->pos=0;
+ }
+
+ public function current() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ return $this->myContent[$this->pos];
+ }
+
+ public function key() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ return "meal " . $this->pos;
+ }
+
+}
+
+$f = new MealIterator;
+var_dump($f);
+
+echo "-----( Simple iteration: )-----\n";
+foreach ($f as $k=>$v) {
+ echo "$k => $v\n";
+}
+
+$f->rewind();
+
+$indent = " ";
+
+echo "\n\n\n-----( Nested iteration: )-----\n";
+$count=1;
+foreach ($f as $k=>$v) {
+ echo "\nTop level " . $count++ . ": \n";
+ echo "$k => $v\n";
+ $indent = " ";
+ foreach ($f as $k=>$v) {
+ echo " $k => $v\n";
+ }
+ $indent = " ";
+
+}
+
+
+?>
+===DONE===
+--EXPECTF--
+object(MealIterator)#%d (2) {
+ [u"pos":u"MealIterator":private]=>
+ int(0)
+ [u"myContent":u"MealIterator":private]=>
+ array(3) {
+ [0]=>
+ unicode(9) "breakfast"
+ [1]=>
+ unicode(5) "lunch"
+ [2]=>
+ unicode(6) "dinner"
+ }
+}
+-----( Simple iteration: )-----
+--> MealIterator::rewind (0)
+--> MealIterator::valid (0)
+--> MealIterator::current (0)
+--> MealIterator::key (0)
+meal 0 => breakfast
+--> MealIterator::next (0)
+--> MealIterator::valid (1)
+--> MealIterator::current (1)
+--> MealIterator::key (1)
+meal 1 => lunch
+--> MealIterator::next (1)
+--> MealIterator::valid (2)
+--> MealIterator::current (2)
+--> MealIterator::key (2)
+meal 2 => dinner
+--> MealIterator::next (2)
+--> MealIterator::valid (3)
+--> MealIterator::rewind (3)
+
+
+
+-----( Nested iteration: )-----
+ --> MealIterator::rewind (0)
+ --> MealIterator::valid (0)
+ --> MealIterator::current (0)
+ --> MealIterator::key (0)
+
+Top level 1:
+meal 0 => breakfast
+ --> MealIterator::rewind (0)
+ --> MealIterator::valid (0)
+ --> MealIterator::current (0)
+ --> MealIterator::key (0)
+ meal 0 => breakfast
+ --> MealIterator::next (0)
+ --> MealIterator::valid (1)
+ --> MealIterator::current (1)
+ --> MealIterator::key (1)
+ meal 1 => lunch
+ --> MealIterator::next (1)
+ --> MealIterator::valid (2)
+ --> MealIterator::current (2)
+ --> MealIterator::key (2)
+ meal 2 => dinner
+ --> MealIterator::next (2)
+ --> MealIterator::valid (3)
+ --> MealIterator::next (3)
+
+Notice: Undefined offset: 3 in %s on line %d
+ --> MealIterator::valid (4)
+===DONE===
\ No newline at end of file
--- /dev/null
+--TEST--
+foreach with iterator and &$value reference
+--FILE--
+<?php
+
+class MyIterator implements Iterator {
+ public function valid() { return true; }
+ public function next() { }
+ public function rewind() { }
+ public function current() { }
+ public function key() { }
+}
+
+$f = new MyIterator;
+echo "-----( Try to iterate with &\$value: )-----\n";
+foreach ($f as $k=>&$v) {
+ echo "$k => $v\n";
+}
+
+?>
+--EXPECTF--
+-----( Try to iterate with &$value: )-----
+
+Fatal error: An iterator cannot be used with foreach by reference in %s on line 13
\ No newline at end of file
--- /dev/null
+--TEST--
+foreach with iteratorAggregate
+--INI--
+unicode.script_encoding=ISO-8859-1
+unicode.runtime_encoding=ISO-8859-1
+--FILE--
+<?php
+class EnglishMealIterator implements Iterator {
+ private $pos=0;
+ private $myContent=array("breakfast", "dinner", "tea");
+
+ public function valid() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ return $this->pos < count($this->myContent);
+ }
+
+ public function next() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ $this->pos++;
+ }
+
+ public function rewind() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ $this->pos=0;
+ }
+
+ public function current() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ return $this->myContent[$this->pos];
+ }
+
+ public function key() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ return "meal " . $this->pos;
+ }
+
+}
+
+class FrenchMealIterator implements Iterator {
+ private $pos=0;
+ private $myContent=array("petit dejeuner", "dejeuner", "gouter", "dinner");
+
+ public function valid() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ return $this->pos < count($this->myContent);
+ }
+
+ public function next() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ $this->pos++;
+ }
+
+ public function rewind() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ $this->pos=0;
+ }
+
+ public function current() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ return $this->myContent[$this->pos];
+ }
+
+ public function key() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ return "meal " . $this->pos;
+ }
+
+}
+
+
+Class EuropeanMeals implements IteratorAggregate {
+
+ private $storedEnglishMealIterator;
+ private $storedFrenchMealIterator;
+
+ public function __construct() {
+ $this->storedEnglishMealIterator = new EnglishMealIterator;
+ $this->storedFrenchMealIterator = new FrenchMealIterator;
+ }
+
+ public function getIterator() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . "\n";
+
+ //Alternate between English and French meals
+ static $i = 0;
+ if ($i++%2 == 0) {
+ return $this->storedEnglishMealIterator;
+ } else {
+ return $this->storedFrenchMealIterator;
+ }
+ }
+
+}
+
+$f = new EuropeanMeals;
+var_dump($f);
+
+echo "-----( Simple iteration 1: )-----\n";
+foreach ($f as $k=>$v) {
+ echo "$k => $v\n";
+}
+echo "-----( Simple iteration 2: )-----\n";
+foreach ($f as $k=>$v) {
+ echo "$k => $v\n";
+}
+
+
+$indent = " ";
+echo "\n\n\n-----( Nested iteration: )-----\n";
+$count=1;
+foreach ($f as $k=>$v) {
+ echo "\nTop level " . $count++ . ": \n";
+ echo "$k => $v\n";
+ $indent = " ";
+ foreach ($f as $k=>$v) {
+ echo " $k => $v\n";
+ }
+ $indent = " ";
+}
+
+
+?>
+===DONE===
+--EXPECTF--
+object(EuropeanMeals)#%d (2) {
+ [u"storedEnglishMealIterator":u"EuropeanMeals":private]=>
+ object(EnglishMealIterator)#%d (2) {
+ [u"pos":u"EnglishMealIterator":private]=>
+ int(0)
+ [u"myContent":u"EnglishMealIterator":private]=>
+ array(3) {
+ [0]=>
+ unicode(9) "breakfast"
+ [1]=>
+ unicode(6) "dinner"
+ [2]=>
+ unicode(3) "tea"
+ }
+ }
+ [u"storedFrenchMealIterator":u"EuropeanMeals":private]=>
+ object(FrenchMealIterator)#%d (2) {
+ [u"pos":u"FrenchMealIterator":private]=>
+ int(0)
+ [u"myContent":u"FrenchMealIterator":private]=>
+ array(4) {
+ [0]=>
+ unicode(14) "petit dejeuner"
+ [1]=>
+ unicode(8) "dejeuner"
+ [2]=>
+ unicode(6) "gouter"
+ [3]=>
+ unicode(6) "dinner"
+ }
+ }
+}
+-----( Simple iteration 1: )-----
+--> EuropeanMeals::getIterator
+--> EnglishMealIterator::rewind (0)
+--> EnglishMealIterator::valid (0)
+--> EnglishMealIterator::current (0)
+--> EnglishMealIterator::key (0)
+meal 0 => breakfast
+--> EnglishMealIterator::next (0)
+--> EnglishMealIterator::valid (1)
+--> EnglishMealIterator::current (1)
+--> EnglishMealIterator::key (1)
+meal 1 => dinner
+--> EnglishMealIterator::next (1)
+--> EnglishMealIterator::valid (2)
+--> EnglishMealIterator::current (2)
+--> EnglishMealIterator::key (2)
+meal 2 => tea
+--> EnglishMealIterator::next (2)
+--> EnglishMealIterator::valid (3)
+-----( Simple iteration 2: )-----
+--> EuropeanMeals::getIterator
+--> FrenchMealIterator::rewind (0)
+--> FrenchMealIterator::valid (0)
+--> FrenchMealIterator::current (0)
+--> FrenchMealIterator::key (0)
+meal 0 => petit dejeuner
+--> FrenchMealIterator::next (0)
+--> FrenchMealIterator::valid (1)
+--> FrenchMealIterator::current (1)
+--> FrenchMealIterator::key (1)
+meal 1 => dejeuner
+--> FrenchMealIterator::next (1)
+--> FrenchMealIterator::valid (2)
+--> FrenchMealIterator::current (2)
+--> FrenchMealIterator::key (2)
+meal 2 => gouter
+--> FrenchMealIterator::next (2)
+--> FrenchMealIterator::valid (3)
+--> FrenchMealIterator::current (3)
+--> FrenchMealIterator::key (3)
+meal 3 => dinner
+--> FrenchMealIterator::next (3)
+--> FrenchMealIterator::valid (4)
+
+
+
+-----( Nested iteration: )-----
+ --> EuropeanMeals::getIterator
+ --> EnglishMealIterator::rewind (3)
+ --> EnglishMealIterator::valid (0)
+ --> EnglishMealIterator::current (0)
+ --> EnglishMealIterator::key (0)
+
+Top level 1:
+meal 0 => breakfast
+ --> EuropeanMeals::getIterator
+ --> FrenchMealIterator::rewind (4)
+ --> FrenchMealIterator::valid (0)
+ --> FrenchMealIterator::current (0)
+ --> FrenchMealIterator::key (0)
+ meal 0 => petit dejeuner
+ --> FrenchMealIterator::next (0)
+ --> FrenchMealIterator::valid (1)
+ --> FrenchMealIterator::current (1)
+ --> FrenchMealIterator::key (1)
+ meal 1 => dejeuner
+ --> FrenchMealIterator::next (1)
+ --> FrenchMealIterator::valid (2)
+ --> FrenchMealIterator::current (2)
+ --> FrenchMealIterator::key (2)
+ meal 2 => gouter
+ --> FrenchMealIterator::next (2)
+ --> FrenchMealIterator::valid (3)
+ --> FrenchMealIterator::current (3)
+ --> FrenchMealIterator::key (3)
+ meal 3 => dinner
+ --> FrenchMealIterator::next (3)
+ --> FrenchMealIterator::valid (4)
+ --> EnglishMealIterator::next (0)
+ --> EnglishMealIterator::valid (1)
+ --> EnglishMealIterator::current (1)
+ --> EnglishMealIterator::key (1)
+
+Top level 2:
+meal 1 => dinner
+ --> EuropeanMeals::getIterator
+ --> EnglishMealIterator::rewind (1)
+ --> EnglishMealIterator::valid (0)
+ --> EnglishMealIterator::current (0)
+ --> EnglishMealIterator::key (0)
+ meal 0 => breakfast
+ --> EnglishMealIterator::next (0)
+ --> EnglishMealIterator::valid (1)
+ --> EnglishMealIterator::current (1)
+ --> EnglishMealIterator::key (1)
+ meal 1 => dinner
+ --> EnglishMealIterator::next (1)
+ --> EnglishMealIterator::valid (2)
+ --> EnglishMealIterator::current (2)
+ --> EnglishMealIterator::key (2)
+ meal 2 => tea
+ --> EnglishMealIterator::next (2)
+ --> EnglishMealIterator::valid (3)
+ --> EnglishMealIterator::next (3)
+ --> EnglishMealIterator::valid (4)
+===DONE===
\ No newline at end of file
--- /dev/null
+--TEST--
+IteratorAggregate::getIterator bad return type
+--FILE--
+<?php
+
+class bad1 implements IteratorAggregate {
+ function getIterator() {
+ return null;
+ }
+}
+
+class bad2 implements IteratorAggregate {
+ function getIterator() {
+ return new stdClass;
+ }
+}
+
+class bad3 implements IteratorAggregate {
+ function getIterator() {
+ return 1;
+ }
+}
+
+class bad4 implements IteratorAggregate {
+ function getIterator() {
+ return array(1,2,3);
+ }
+}
+
+
+function f($className) {
+ try {
+ foreach (new $className as $k=>$v) {
+ echo "$k => $v\n";
+ }
+ } catch (Exception $e) {
+ echo $e->getLine() . ": " . $e->getMessage() ."\n";
+ }
+}
+
+f("bad1");
+f("bad2");
+f("bad3");
+f("bad4");
+
+?>
+===DONE===
+--EXPECTF--
+30: Objects returned by bad1::getIterator() must be traversable or implement interface Iterator
+30: Objects returned by bad2::getIterator() must be traversable or implement interface Iterator
+30: Objects returned by bad3::getIterator() must be traversable or implement interface Iterator
+30: Objects returned by bad4::getIterator() must be traversable or implement interface Iterator
+===DONE===
\ No newline at end of file
--- /dev/null
+--TEST--
+foreach with nested iteratorAggregates
+--FILE--
+<?php
+class EnglishMealIterator implements Iterator {
+ private $pos=0;
+ private $myContent=array("breakfast", "dinner", "tea");
+
+ public function valid() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ return $this->pos<3;
+ }
+
+ public function next() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ return $this->myContent[$this->pos++];
+ }
+
+ public function rewind() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ $this->pos=0;
+ }
+
+ public function current() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ return $this->myContent[$this->pos];
+ }
+
+ public function key() {
+ global $indent;
+ echo "$indent--> " . __METHOD__ . " ($this->pos)\n";
+ return "meal " . $this->pos;
+ }
+
+}
+
+class A1 implements IteratorAggregate {
+ function getIterator() {
+ return new EnglishMealIterator;
+ }
+}
+
+class A2 implements IteratorAggregate {
+ function getIterator() {
+ return new A1;
+ }
+}
+
+class A3 implements IteratorAggregate {
+ function getIterator() {
+ return new A2;
+ }
+}
+
+echo "\n-----( A1: )-----\n";
+foreach (new A1 as $k=>$v) {
+ echo "$k => $v\n";
+}
+
+echo "\n-----( A2: )-----\n";
+foreach (new A2 as $k=>$v) {
+ echo "$k => $v\n";
+}
+
+echo "\n-----( A3: )-----\n";
+foreach (new A3 as $k=>$v) {
+ echo "$k => $v\n";
+}
+
+
+?>
+===DONE===
+--EXPECTF--
+-----( A1: )-----
+--> EnglishMealIterator::rewind (0)
+--> EnglishMealIterator::valid (0)
+--> EnglishMealIterator::current (0)
+--> EnglishMealIterator::key (0)
+meal 0 => breakfast
+--> EnglishMealIterator::next (0)
+--> EnglishMealIterator::valid (1)
+--> EnglishMealIterator::current (1)
+--> EnglishMealIterator::key (1)
+meal 1 => dinner
+--> EnglishMealIterator::next (1)
+--> EnglishMealIterator::valid (2)
+--> EnglishMealIterator::current (2)
+--> EnglishMealIterator::key (2)
+meal 2 => tea
+--> EnglishMealIterator::next (2)
+--> EnglishMealIterator::valid (3)
+
+-----( A2: )-----
+--> EnglishMealIterator::rewind (0)
+--> EnglishMealIterator::valid (0)
+--> EnglishMealIterator::current (0)
+--> EnglishMealIterator::key (0)
+meal 0 => breakfast
+--> EnglishMealIterator::next (0)
+--> EnglishMealIterator::valid (1)
+--> EnglishMealIterator::current (1)
+--> EnglishMealIterator::key (1)
+meal 1 => dinner
+--> EnglishMealIterator::next (1)
+--> EnglishMealIterator::valid (2)
+--> EnglishMealIterator::current (2)
+--> EnglishMealIterator::key (2)
+meal 2 => tea
+--> EnglishMealIterator::next (2)
+--> EnglishMealIterator::valid (3)
+
+-----( A3: )-----
+--> EnglishMealIterator::rewind (0)
+--> EnglishMealIterator::valid (0)
+--> EnglishMealIterator::current (0)
+--> EnglishMealIterator::key (0)
+meal 0 => breakfast
+--> EnglishMealIterator::next (0)
+--> EnglishMealIterator::valid (1)
+--> EnglishMealIterator::current (1)
+--> EnglishMealIterator::key (1)
+meal 1 => dinner
+--> EnglishMealIterator::next (1)
+--> EnglishMealIterator::valid (2)
+--> EnglishMealIterator::current (2)
+--> EnglishMealIterator::key (2)
+meal 2 => tea
+--> EnglishMealIterator::next (2)
+--> EnglishMealIterator::valid (3)
+===DONE===
--- /dev/null
+--TEST--
+Duplicate of zend test tests/classes/iterators_002.phpt without expected output from destructor
+--FILE--
+<?php
+class c_iter implements Iterator {
+
+ private $obj;
+ private $num = 0;
+
+ function __construct($obj) {
+ echo __METHOD__ . "\n";
+ $this->obj = $obj;
+ }
+ function rewind() {
+ echo __METHOD__ . "\n";
+ $this->num = 0;
+ }
+ function valid() {
+ $more = $this->num < $this->obj->max;
+ echo __METHOD__ . ' = ' .($more ? 'true' : 'false') . "\n";
+ return $more;
+ }
+ function current() {
+ echo __METHOD__ . "\n";
+ return $this->num;
+ }
+ function next() {
+ echo __METHOD__ . "\n";
+ $this->num++;
+ }
+ function key() {
+ echo __METHOD__ . "\n";
+ switch($this->num) {
+ case 0: return "1st";
+ case 1: return "2nd";
+ case 2: return "3rd";
+ default: return "???";
+ }
+ }
+ function __destruct() {
+ }
+}
+
+class c implements IteratorAggregate {
+
+ public $max = 3;
+
+ function getIterator() {
+ echo __METHOD__ . "\n";
+ return new c_iter($this);
+ }
+ function __destruct() {
+ }
+}
+
+$t = new c();
+
+foreach($t as $k => $v) {
+ foreach($t as $w) {
+ echo "double:$v:$w\n";
+ break;
+ }
+}
+
+unset($t);
+
+?>
+===DONE===
+--EXPECT--
+c::getIterator
+c_iter::__construct
+c_iter::rewind
+c_iter::valid = true
+c_iter::current
+c_iter::key
+c::getIterator
+c_iter::__construct
+c_iter::rewind
+c_iter::valid = true
+c_iter::current
+double:0:0
+c_iter::next
+c_iter::valid = true
+c_iter::current
+c_iter::key
+c::getIterator
+c_iter::__construct
+c_iter::rewind
+c_iter::valid = true
+c_iter::current
+double:1:0
+c_iter::next
+c_iter::valid = true
+c_iter::current
+c_iter::key
+c::getIterator
+c_iter::__construct
+c_iter::rewind
+c_iter::valid = true
+c_iter::current
+double:2:0
+c_iter::next
+c_iter::valid = false
+===DONE===