You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

236 lines
4.9 KiB

22 years ago
22 years ago
22 years ago
22 years ago
22 years ago
22 years ago
22 years ago
23 years ago
22 years ago
23 years ago
22 years ago
23 years ago
23 years ago
23 years ago
22 years ago
22 years ago
23 years ago
22 years ago
23 years ago
22 years ago
23 years ago
23 years ago
21 years ago
23 years ago
23 years ago
22 years ago
23 years ago
22 years ago
23 years ago
21 years ago
21 years ago
21 years ago
20 years ago
20 years ago
  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. ?>