1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
|
<?php
/** @file cachingiterator.inc
* @ingroup SPL
* @brief class CachingIterator
* @author Marcus Boerger
* @date 2003 - 2009
*
* SPL - Standard PHP Library
*/
/**
* @brief Cached iteration over another Iterator
* @author Marcus Boerger
* @version 1.2
* @since PHP 5.0
*
* This iterator wrapper does a one ahead iteration. This way it knows whether
* the inner iterator has one more element.
*
* @note If you want to convert the elements into strings and the inner
* Iterator is an internal Iterator then you need to provide the
* flag CALL_TOSTRING to do the conversion when the actual element
* is being fetched. Otherwise the conversion would happen with the
* already changed iterator. If you do not need this then it you should
* omit this flag because it costs unnecessary work and time.
*/
class CachingIterator implements OuterIterator
{
const CALL_TOSTRING = 0x00000001;
const CATCH_GET_CHILD = 0x00000002;
const TOSTRING_USE_KEY = 0x00000010;
const TOSTRING_USE_CURRENT = 0x00000020;
private $it;
private $current;
private $key;
private $valid;
private $strValue;
/** Construct from another iterator
*
* @param it Iterator to cache
* @param flags Bitmask:
* - CALL_TOSTRING (whether to call __toString() for every element)
*/
function __construct(Iterator $it, $flags = self::CALL_TOSTRING)
{
if ((($flags & self::CALL_TOSTRING) && ($flags & (self::TOSTRING_USE_KEY|self::TOSTRING_USE_CURRENT)))
|| ((flags & (self::CIT_TOSTRING_USE_KEY|self::CIT_TOSTRING_USE_CURRENT)) == (self::CIT_TOSTRING_USE_KEY|self::CIT_TOSTRING_USE_CURRENT)))
{
throw new InvalidArgumentException('Flags must contain only one of CIT_CALL_TOSTRING, CIT_TOSTRING_USE_KEY, CIT_TOSTRING_USE_CURRENT');
}
$this->it = $it;
$this->flags = $flags & (0x0000FFFF);
$this->next();
}
/** Rewind the Iterator
*/
function rewind()
{
$this->it->rewind();
$this->next();
}
/** Forward to the next element
*/
function next()
{
if ($this->valid = $this->it->valid()) {
$this->current = $this->it->current();
$this->key = $this->it->key();
if ($this->flags & self::CALL_TOSTRING) {
if (is_object($this->current)) {
$this->strValue = $this->current->__toString();
} else {
$this->strValue = (string)$this->current;
}
}
} else {
$this->current = NULL;
$this->key = NULL;
$this->strValue = NULL;
}
$this->it->next();
}
/** @return whether the iterator is valid
*/
function valid()
{
return $this->valid;
}
/** @return whether there is one more element
*/
function hasNext()
{
return $this->it->valid();
}
/** @return the current element
*/
function current()
{
return $this->current;
}
/** @return the current key
*/
function key()
{
return $this->key;
}
/** Aggregate the inner iterator
*
* @param func Name of method to invoke
* @param params Array of parameters to pass to method
*/
function __call($func, $params)
{
return call_user_func_array(array($this->it, $func), $params);
}
/** @return the string represenatation that was generated for the current
* element
* @throw exception when CALL_TOSTRING was not specified in constructor
*/
function __toString()
{
if ($this->flags & self::TOSTRING_USE_KEY)
{
return $this->key;
}
else if ($this->flags & self::TOSTRING_USE_CURRENT)
{
return $this->current;
}
if (!$this->flags & self::CALL_TOSTRING)
{
throw new exception('CachingIterator does not fetch string value (see CachingIterator::__construct)');
}
return $this->strValue;
}
/**
* @return The inner iterator
*/
function getInnerIterator()
{
return $this->it;
}
}
?>
|