recursiveiteratoriterator.inc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <?php
  2. /** @file recursiveiteratoriterator.inc
  3. * @ingroup SPL
  4. * @brief class RecursiveIteratorIterator
  5. * @author Marcus Boerger
  6. * @date 2003 - 2009
  7. *
  8. * SPL - Standard PHP Library
  9. */
  10. /**
  11. * @brief Iterates through recursive iterators
  12. * @author Marcus Boerger
  13. * @version 1.2
  14. * @since PHP 5.0
  15. *
  16. * The objects of this class are created by instances of RecursiveIterator.
  17. * Elements of those iterators may be traversable themselves. If so these
  18. * sub elements are recursed into.
  19. */
  20. class RecursiveIteratorIterator implements OuterIterator
  21. {
  22. /** Mode: Only show leaves */
  23. const LEAVES_ONLY = 0;
  24. /** Mode: Show parents prior to their children */
  25. const SELF_FIRST = 1;
  26. /** Mode: Show all children prior to their parent */
  27. const CHILD_FIRST = 2;
  28. /** Flag: Catches exceptions during getChildren() calls and simply jumps
  29. * to the next element. */
  30. const CATCH_GET_CHILD = 0x00000002;
  31. private $ait = array();
  32. private $count = 0;
  33. private $mode = self::LEAVES_ONLY;
  34. private $flags = 0;
  35. /** Construct from RecursiveIterator
  36. *
  37. * @param it RecursiveIterator to iterate
  38. * @param mode Operation mode (one of):
  39. * - LEAVES_ONLY only show leaves
  40. * - SELF_FIRST show parents prior to their childs
  41. * - CHILD_FIRST show all children prior to their parent
  42. * @param flags Control flags, zero or any combination of the following
  43. * (since PHP 5.1).
  44. * - CATCH_GET_CHILD which catches exceptions during
  45. * getChildren() calls and simply jumps to the next
  46. * element.
  47. */
  48. function __construct(RecursiveIterator $it, $mode = self::LEAVES_ONLY, $flags = 0)
  49. {
  50. $this->ait[0] = $it;
  51. $this->mode = $mode;
  52. $this->flags = $flags;
  53. }
  54. /** Rewind to top iterator as set in constructor
  55. */
  56. function rewind()
  57. {
  58. while ($this->count) {
  59. unset($this->ait[$this->count--]);
  60. $this->endChildren();
  61. }
  62. $this->ait[0]->rewind();
  63. $this->ait[0]->recursed = false;
  64. callNextElement(true);
  65. }
  66. /** @return whether iterator is valid
  67. */
  68. function valid()
  69. {
  70. $count = $this->count;
  71. while ($count) {
  72. $it = $this->ait[$count];
  73. if ($it->valid()) {
  74. return true;
  75. }
  76. $count--;
  77. $this->endChildren();
  78. }
  79. return false;
  80. }
  81. /** @return current key
  82. */
  83. function key()
  84. {
  85. $it = $this->ait[$this->count];
  86. return $it->key();
  87. }
  88. /** @return current element
  89. */
  90. function current()
  91. {
  92. $it = $this->ait[$this->count];
  93. return $it->current();
  94. }
  95. /** Forward to next element
  96. */
  97. function next()
  98. {
  99. while ($this->count) {
  100. $it = $this->ait[$this->count];
  101. if ($it->valid()) {
  102. if (!$it->recursed && callHasChildren()) {
  103. $it->recursed = true;
  104. try
  105. {
  106. $sub = callGetChildren();
  107. }
  108. catch (Exception $e)
  109. {
  110. if (!($this->flags & self::CATCH_GET_CHILD))
  111. {
  112. throw $e;
  113. }
  114. $it->next();
  115. continue;
  116. }
  117. $sub->recursed = false;
  118. $sub->rewind();
  119. if ($sub->valid()) {
  120. $this->ait[++$this->count] = $sub;
  121. if (!$sub instanceof RecursiveIterator) {
  122. throw new Exception(get_class($sub).'::getChildren() must return an object that implements RecursiveIterator');
  123. }
  124. $this->beginChildren();
  125. return;
  126. }
  127. unset($sub);
  128. }
  129. $it->next();
  130. $it->recursed = false;
  131. if ($it->valid()) {
  132. return;
  133. }
  134. $it->recursed = false;
  135. }
  136. if ($this->count) {
  137. unset($this->ait[$this->count--]);
  138. $it = $this->ait[$this->count];
  139. $this->endChildren();
  140. callNextElement(false);
  141. }
  142. }
  143. callNextElement(true);
  144. }
  145. /** @return Sub Iterator at given level or if unspecified the current sub
  146. * Iterator
  147. */
  148. function getSubIterator($level = NULL)
  149. {
  150. if (is_null($level)) {
  151. $level = $this->count;
  152. }
  153. return @$this->ait[$level];
  154. }
  155. /**
  156. * @return The inner iterator
  157. */
  158. function getInnerIterator()
  159. {
  160. return $this->it;
  161. }
  162. /** @return Current Depth (Number of parents)
  163. */
  164. function getDepth()
  165. {
  166. return $this->level;
  167. }
  168. /** @return whether current sub iterators current element has children
  169. * @since PHP 5.1
  170. */
  171. function callHasChildren()
  172. {
  173. return $this->ait[$this->count]->hasChildren();
  174. }
  175. /** @return current sub iterators current children
  176. * @since PHP 5.1
  177. */
  178. function callGetChildren()
  179. {
  180. return $this->ait[$this->count]->getChildren();
  181. }
  182. /** Called right after calling getChildren() and its rewind().
  183. * @since PHP 5.1
  184. */
  185. function beginChildren()
  186. {
  187. }
  188. /** Called after current child iterator is invalid and right before it
  189. * gets destructed.
  190. * @since PHP 5.1
  191. */
  192. function endChildren()
  193. {
  194. }
  195. private function callNextElement($after_move)
  196. {
  197. if ($this->valid())
  198. {
  199. if ($after_move)
  200. {
  201. if (($this->mode == self::SELF_FIRST && $this->callHasChildren())
  202. || $this->mode == self::LEAVES_ONLY)
  203. $this->nextElement();
  204. }
  205. else
  206. {
  207. $this->nextElement();
  208. }
  209. }
  210. }
  211. /** Called when the next element is available
  212. */
  213. function nextElement()
  214. {
  215. }
  216. }
  217. ?>