<?php
/** @file multipleiterator.inc
* @ingroup SPL
* @brief class MultipleIterator
* @author Johannes Schlueter
* @author Marcus Boerger
* @date 2008 - 2009
*
* SPL - Standard PHP Library
*/
/** @ingroup SPL
* @brief Iterator that iterates over several iterators one after the other
* @author Johannes Schlueter
* @author Marcus Boerger
* @version 1.0
* @since PHP 5.3
*/
class MultipleIterator implements Iterator
{
/** Inner Iterators */
private $iterators;
/** Flags: const MIT_* */
private $flags;
/** do not require all sub iterators to be valid in iteration */
const MIT_NEED_ANY = 0;
/** require all sub iterators to be valid in iteration */
const MIT_NEED_ALL = 1;
/** keys are created from sub iterators position */
const MIT_KEYS_NUMERIC = 0;
/** keys are created from sub iterators associated infromation */
const MIT_KEYS_ASSOC = 2;
/** Construct a new empty MultipleIterator
* @param flags MIT_* flags
*/
public function __construct($flags = self::MIT_NEED_ALL|self::MIT_KEYS_NUMERIC)
{
$this->iterators = new SplObjectStorage();
$this->flags = $flags;
}
/** @return current flags MIT_* */
public function getFlags()
{
return $this->flags;
}
/** @param $flags new flags. */
public function setFlags($flags)
{
$this->flags = $flags;
}
/** @param $iter new Iterator to attach.
* @param $inf associative info forIteraotr, must be NULL, integer or string
*
* @throws IllegalValueException if a inf is none of NULL, integer or string
* @throws IllegalValueException if a inf is already an associated info
*/
public function attachIterator(Iterator $iter, $inf = NULL)
{
if (!is_null($inf))
{
if (!is_int($inf) && !is_string($inf))
{
throw new IllegalValueException('Inf must be NULL, integer or string');
}
foreach($this->iterators as $iter)
{
if ($inf == $this->iterators->getInfo())
{
throw new IllegalValueException('Key duplication error');
}
}
}
$this->iterators->attach($iter, $inf);
}
/** @param $iter attached Iterator that should be detached. */
public function detachIterator(Iterator $iter)
{
$this->iterators->detach($iter);
}
/** @param $iter Iterator to check
* @return whether $iter is attached or not
*/
public function containsIterator(Iterator $iter)
{
return $this->iterator->contains($iter);
}
/** @return number of attached Iterator instances. */
public function countIterators()
{
return $this->iterators->count();
}
/** Rewind all attached Iterator instances. */
public function rewind()
{
foreach($this->iterators as $iter)
{
$iter->rewind();
}
}
/**
* @return whether all or one sub iterator is valid depending on flags.
* In mode MIT_NEED_ALL we expect all sub iterators to be valid and
* return flase on the first non valid one. If that flag is not set we
* return true on the first valid sub iterator found. If no Iterator
* is attached, we always return false.
*/
public function valid()
{
if (!sizeof($this->iterators)) {
return false;
}
// The following code is an optimized version that executes as few
// valid() calls as necessary and that only checks the flags once.
$expect = $this->flags & self::MIT_NEED_ALL ? true : false;
foreach($this->iterators as $iter)
{
if ($expect != $iter->valid())
{
return !$expect;
}
}
return $expect;
}
/** Move all attached Iterator instances forward. That is invoke
* their next() method regardless of their state.
*/
public function next()
{
foreach($this->iterators as $iter)
{
$iter->next();
}
}
/** @return false if no sub Iterator is attached and an array of
* all registered Iterator instances current() result.
* @throws RuntimeException if mode MIT_NEED_ALL is set and at least one
* attached Iterator is not valid().
* @throws IllegalValueException if a key is NULL and MIT_KEYS_ASSOC is set.
*/
public function current()
{
if (!sizeof($this->iterators))
{
return false;
}
$retval = array();
foreach($this->iterators as $iter)
{
if ($iter->valid())
{
if ($this->flags & self::MIT_KEYS_ASSOC)
{
$key = $this->iterators->getInfo();
if (is_null($key))
{
throw new IllegalValueException('Sub-Iterator is associated with NULL');
}
$retval[$key] = $iter->current();
}
else
{
$retval[] = $iter->current();
}
}
else if ($this->flags & self::MIT_NEED_ALL)
{
throw new RuntimeException('Called current() with non valid sub iterator');
}
else
{
$retval[] = NULL;
}
}
return $retval;
}
/** @return false if no sub Iterator is attached and an array of
* all registered Iterator instances key() result.
* @throws LogicException if mode MIT_NEED_ALL is set and at least one
* attached Iterator is not valid().
*/
public function key()
{
if (!sizeof($this->iterators))
{
return false;
}
$retval = array();
foreach($this->iterators as $iter)
{
if ($iter->valid())
{
$retval[] = $iter->key();
}
else if ($this->flags & self::MIT_NEED_ALL)
{
throw new LogicException('Called key() with non valid sub iterator');
}
else
{
$retval[] = NULL;
}
}
return $retval;
}
}
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>