summaryrefslogtreecommitdiff
path: root/ext/spl/internal/recursiveiteratoriterator.inc
diff options
context:
space:
mode:
Diffstat (limited to 'ext/spl/internal/recursiveiteratoriterator.inc')
-rw-r--r--ext/spl/internal/recursiveiteratoriterator.inc237
1 files changed, 237 insertions, 0 deletions
diff --git a/ext/spl/internal/recursiveiteratoriterator.inc b/ext/spl/internal/recursiveiteratoriterator.inc
new file mode 100644
index 0000000..35fa801
--- /dev/null
+++ b/ext/spl/internal/recursiveiteratoriterator.inc
@@ -0,0 +1,237 @@
+<?php
+
+/** @file recursiveiteratoriterator.inc
+ * @ingroup SPL
+ * @brief class RecursiveIteratorIterator
+ * @author Marcus Boerger
+ * @date 2003 - 2009
+ *
+ * SPL - Standard PHP Library
+ */
+
+/**
+ * @brief Iterates through recursive iterators
+ * @author Marcus Boerger
+ * @version 1.2
+ * @since PHP 5.0
+ *
+ * The objects of this class are created by instances of RecursiveIterator.
+ * Elements of those iterators may be traversable themselves. If so these
+ * sub elements are recursed into.
+ */
+class RecursiveIteratorIterator implements OuterIterator
+{
+ /** Mode: Only show leaves */
+ const LEAVES_ONLY = 0;
+ /** Mode: Show parents prior to their children */
+ const SELF_FIRST = 1;
+ /** Mode: Show all children prior to their parent */
+ const CHILD_FIRST = 2;
+
+ /** Flag: Catches exceptions during getChildren() calls and simply jumps
+ * to the next element. */
+ const CATCH_GET_CHILD = 0x00000002;
+
+ private $ait = array();
+ private $count = 0;
+ private $mode = self::LEAVES_ONLY;
+ private $flags = 0;
+
+ /** Construct from RecursiveIterator
+ *
+ * @param it RecursiveIterator to iterate
+ * @param mode Operation mode (one of):
+ * - LEAVES_ONLY only show leaves
+ * - SELF_FIRST show parents prior to their childs
+ * - CHILD_FIRST show all children prior to their parent
+ * @param flags Control flags, zero or any combination of the following
+ * (since PHP 5.1).
+ * - CATCH_GET_CHILD which catches exceptions during
+ * getChildren() calls and simply jumps to the next
+ * element.
+ */
+ function __construct(RecursiveIterator $it, $mode = self::LEAVES_ONLY, $flags = 0)
+ {
+ $this->ait[0] = $it;
+ $this->mode = $mode;
+ $this->flags = $flags;
+ }
+
+ /** Rewind to top iterator as set in constructor
+ */
+ function rewind()
+ {
+ while ($this->count) {
+ unset($this->ait[$this->count--]);
+ $this->endChildren();
+ }
+ $this->ait[0]->rewind();
+ $this->ait[0]->recursed = false;
+ callNextElement(true);
+ }
+
+ /** @return whether iterator is valid
+ */
+ function valid()
+ {
+ $count = $this->count;
+ while ($count) {
+ $it = $this->ait[$count];
+ if ($it->valid()) {
+ return true;
+ }
+ $count--;
+ $this->endChildren();
+ }
+ return false;
+ }
+
+ /** @return current key
+ */
+ function key()
+ {
+ $it = $this->ait[$this->count];
+ return $it->key();
+ }
+
+ /** @return current element
+ */
+ function current()
+ {
+ $it = $this->ait[$this->count];
+ return $it->current();
+ }
+
+ /** Forward to next element
+ */
+ function next()
+ {
+ while ($this->count) {
+ $it = $this->ait[$this->count];
+ if ($it->valid()) {
+ if (!$it->recursed && callHasChildren()) {
+ $it->recursed = true;
+ try
+ {
+ $sub = callGetChildren();
+ }
+ catch (Exception $e)
+ {
+ if (!($this->flags & self::CATCH_GET_CHILD))
+ {
+ throw $e;
+ }
+ $it->next();
+ continue;
+ }
+ $sub->recursed = false;
+ $sub->rewind();
+ if ($sub->valid()) {
+ $this->ait[++$this->count] = $sub;
+ if (!$sub instanceof RecursiveIterator) {
+ throw new Exception(get_class($sub).'::getChildren() must return an object that implements RecursiveIterator');
+ }
+ $this->beginChildren();
+ return;
+ }
+ unset($sub);
+ }
+ $it->next();
+ $it->recursed = false;
+ if ($it->valid()) {
+ return;
+ }
+ $it->recursed = false;
+ }
+ if ($this->count) {
+ unset($this->ait[$this->count--]);
+ $it = $this->ait[$this->count];
+ $this->endChildren();
+ callNextElement(false);
+ }
+ }
+ callNextElement(true);
+ }
+
+ /** @return Sub Iterator at given level or if unspecified the current sub
+ * Iterator
+ */
+ function getSubIterator($level = NULL)
+ {
+ if (is_null($level)) {
+ $level = $this->count;
+ }
+ return @$this->ait[$level];
+ }
+
+ /**
+ * @return The inner iterator
+ */
+ function getInnerIterator()
+ {
+ return $this->it;
+ }
+
+ /** @return Current Depth (Number of parents)
+ */
+ function getDepth()
+ {
+ return $this->level;
+ }
+
+ /** @return whether current sub iterators current element has children
+ * @since PHP 5.1
+ */
+ function callHasChildren()
+ {
+ return $this->ait[$this->count]->hasChildren();
+ }
+
+ /** @return current sub iterators current children
+ * @since PHP 5.1
+ */
+ function callGetChildren()
+ {
+ return $this->ait[$this->count]->getChildren();
+ }
+
+ /** Called right after calling getChildren() and its rewind().
+ * @since PHP 5.1
+ */
+ function beginChildren()
+ {
+ }
+
+ /** Called after current child iterator is invalid and right before it
+ * gets destructed.
+ * @since PHP 5.1
+ */
+ function endChildren()
+ {
+ }
+
+ private function callNextElement($after_move)
+ {
+ if ($this->valid())
+ {
+ if ($after_move)
+ {
+ if (($this->mode == self::SELF_FIRST && $this->callHasChildren())
+ || $this->mode == self::LEAVES_ONLY)
+ $this->nextElement();
+ }
+ else
+ {
+ $this->nextElement();
+ }
+ }
+ }
+
+ /** Called when the next element is available
+ */
+ function nextElement()
+ {
+ }
+}
+
+?> \ No newline at end of file