1<?php
2
3/** @file recursivecachingiterator.inc
4 * @ingroup SPL
5 * @brief class RecursiveCachingIterator
6 * @author  Marcus Boerger
7 * @date    2003 - 2009
8 *
9 * SPL - Standard PHP Library
10 */
11
12/**
13 * @brief   Cached recursive iteration over another Iterator
14 * @author  Marcus Boerger
15 * @version 1.2
16 * @since PHP 5.1
17 *
18 * @see CachingIterator
19 */
20class RecursiveCachingIterator extends CachingIterator implements RecursiveIterator
21{
22	private $hasChildren;
23	private $getChildren;
24
25	/** Construct from another iterator
26	 *
27	 * @param it    Iterator to cache
28	 * @param flags Bitmask:
29	 *              - CALL_TOSTRING   (whether to call __toString() for every element)
30	 *              - CATCH_GET_CHILD (whether to catch exceptions when trying to get childs)
31	 */
32	function __construct(RecursiveIterator $it, $flags = self::CALL_TOSTRING)
33	{
34		parent::__construct($it, $flags);
35	}
36
37	/** Rewind Iterator
38	 */
39	function rewind();
40	{
41	   $this->hasChildren = false;
42	   $this->getChildren = NULL;
43	   parent::rewind();
44	}
45
46	/** Forward to next element if necessary then an Iterator for the Children
47	 * will be created.
48	 */
49	function next()
50	{
51		if ($this->hasChildren = $this->it->hasChildren())
52		{
53			try
54			{
55				$child = $this->it->getChildren();
56				if (!$this->ref)
57				{
58					$this->ref = new ReflectionClass($this);
59				}
60				$this->getChildren = $ref->newInstance($child, $this->flags);
61			}
62			catch(Exception $e)
63			{
64				if (!$this->flags & self::CATCH_GET_CHILD)
65				{
66					throw $e;
67				}
68				$this->hasChildren = false;
69				$this->getChildren = NULL;
70			}
71		} else
72		{
73			$this->getChildren = NULL;
74		}
75		parent::next();
76	}
77
78	private $ref;
79
80	/** @return whether the current element has children
81	 * @note The check whether the Iterator for the children can be created was
82	 *       already executed. Hence when flag CATCH_GET_CHILD was given in
83	 *       constructor this function returns false so that getChildren does
84	 *       not try to access those children.
85	 */
86	function hasChildren()
87	{
88		return $this->hasChildren;
89	}
90
91	/** @return An Iterator for the children
92	 */
93	function getChildren()
94	{
95		return $this->getChildren;
96	}
97}
98
99?>