-
Notifications
You must be signed in to change notification settings - Fork 5
FilterChain Iterator
salathe edited this page Aug 26, 2010
·
3 revisions
This class extends FilterIterator
and allows registering of multiple arbitrary callbacks to be used in FilterIterator::accept()
. When iterating over the elements in the inner Iterator, the current element will be tested against all registered callbacks. If any callback returns FALSE
, the element is filtered.
Use the FilterChainIterator
when you need to utilize filtering logic from existing code that is not a FilterIterator
itself and/or when creation of a dedicated FilterIterator
would lead to code duplication.
<?php
$filterMultiples = function($currentElement, $multipleOf)
{
return $currentElement % $multipleOf !== 0;
};
$filterRange = function($currentElement, $from, $to)
{
return $currentElement < $from || $currentElement > $to;
};
$filterDoubleDigits = function($currentElement)
{
return strlen($currentElement) == 1 ||
count(count_chars($currentElement, 1)) > 1;
};
$iterator = new FilterChainIterator(new ArrayIterator(range(1, 100)));
$iterator->addCallback($filterMultiples, array(3))
->addCallback($filterMultiples, array(5))
->addCallback($filterMultiples, array(7))
->addCallback($filterRange, array(20,30))
->addCallback($filterRange, array(50,90))
->addCallback($filterDoubleDigits);
foreach($iterator as $number) {
echo "$number,"; // 1,2,4,8,13,16,17,19,31,32,34,37,38,41,43,46,47,92,94,97,
}
<?php
class FilterChainIterator extends FilterIterator
{
/**
* Callback Store
* @var Array
*/
protected $_callbacks = array();
/**
* Adds a callback to the Iterator's callback store
*
* Callbacks registered through this method must accept the current
* element of the iteration as first argument. Any arguments given
* in the second optional argument $arguments will be passed to the
* callback as additional function arguments.
*
* @param Mixed $callback Anything callable
* @param Array $arguments Array of arguments for Callback
* @returns FilterChainIterator
* @throws InvalidArgumentException when $callback is not callable
*/
public function addCallback($callback, $arguments = array())
{
if(!is_callable($callback)) {
throw new InvalidArgumentException(sprintf(
'%s expects argument 1 to be callable', __FUNCTION__
));
}
$this->_callbacks[] = array(
'function' => $callback,
'arguments' => $arguments
);
return $this;
}
/**
* Returns the Callback Store
* @return Array
*/
public function getCallbacks()
{
return $this->_callbacks;
}
/**
* Filters current element by each callback in the Callback Store
*
* @see FilterIterator::accept()
* @return Boolean
*/
public function accept()
{
foreach($this->getCallbacks() as $callback) {
$args = $this->_curryCallbackArguments($callback['arguments']);
$accept = call_user_func_array($callback['function'], $args);
if($accept === FALSE) {
return FALSE;
}
}
return TRUE;
}
/**
* Prepends the arguments array with the current element
*
* @param array $arguments
* @return Array
*/
protected function _curryCallbackArguments(array $arguments)
{
return array_merge(array($this->current()), $arguments);
}
}