Skip to content

Instantly share code, notes, and snippets.

@hakre
Created February 28, 2012 06:59
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save hakre/1930284 to your computer and use it in GitHub Desktop.
Save hakre/1930284 to your computer and use it in GitHub Desktop.
Some Iterator Fun
<?php
/*
* Some Iterator Fun
*
* @link http://hakre.wordpress.com/2012/02/28/some-php-iterator-fun/
*/
/**
* Iterator that fetches each iteration value from a
* function until it is not string and equals false.
*/
class FetchIterator extends NoRewindIterator
{
/**
* @var string
*/
private $fetchCallback;
/**
* number of the current iteration
* @var int
*/
private $virtual;
/**
* cache of the current value
* @var mixed
*/
private $current;
/**
* @param string $fetchCallback
*/
public function __construct($fetchCallback)
{
$this->fetchCallback = $fetchCallback;
$this->virtual = 0;
}
/**
* Return the current element
* @link http://php.net/manual/en/iterator.current.php
* @return mixed Can return any type.
*/
public function current()
{
$this->virtual || $this->next();
return $this->current;
}
/**
* Return the key of the current element
* @link http://php.net/manual/en/iterator.key.php
* @return scalar scalar on success, integer
* 0 on failure.
*/
public function key()
{
$this->virtual || $this->next();
return $this->virtual - 1;
}
/**
* Checks if current position is valid
* @link http://php.net/manual/en/iterator.valid.php
* @return boolean The return value will be casted to boolean and then evaluated.
* Returns true on success or false on failure.
*/
public function valid()
{
$this->virtual || $this->next();
return $this->validate();
}
/**
* @return bool
*/
private function validate()
{
return FALSE != $this->current || is_string($this->current);
}
/**
* Move forward to next element
* @link http://php.net/manual/en/iterator.next.php
* @return void Any returned value is ignored.
*/
public function next()
{
if ($this->virtual && ! $this->validate()) {
return;
}
$this->fetch();
$this->virtual++;
}
/**
* fetch value from callback. can be called
* after assigning a new callback while
* in iteration.
*/
public function fetch()
{
$func = $this->fetchCallback;
$this->current = $func();
}
/**
* number of times the fetch callback function
* has been called so far.
*
* @return int
*/
public function getCallCount()
{
return $this->virtual;
}
/**
* @return callback
*/
public function getFetchCallback()
{
return $this->fetchCallback;
}
/**
* Set callback for subsequent iterations.
*
* @param callback $fetchCallback
* @return FetchIterator
*/
public function setFetchCallback($fetchCallback)
{
$this->fetchCallback = $fetchCallback;
return $this;
}
}
/**
* Iterator that limits the number of iterations if
* there are more than it's size. If there are less
* additional iterations are appended with pad-value.
*/
class PadIterator extends IteratorIterator
{
/**
* @var int
*/
private $pos;
/**
* @var int
*/
private $size;
/**
* @var mixed
*/
private $pad;
/**
* @var int|string
*/
private $key;
/**
* @param Iterator $it
* @param int $size
* @param mixed $with pad-value
*/
public function __construct(Iterator $it, $size = 0, $with = NULL)
{
$this->pos = 0;
$this->size = max(0, $size);
$this->pad = $with;
parent::__construct($it);
}
public function valid()
{
return $this->pos < $this->size;
}
public function next()
{
if ($this->pos + 1 < $this->size) {
parent::next();
}
if ($this->pos + 1 > $this->size) {
return;
}
$this->pos++;
if (is_int($this->key)) {
$this->key++;
} else {
$this->key = $this->pos;
}
}
public function rewind()
{
parent::rewind();
$this->pos = 0;
}
public function current()
{
if (parent::valid()) {
return parent::current();
}
return $this->pad;
}
public function key()
{
if (parent::valid()) {
return $this->key = parent::key();
}
return $this->key;
}
/**
* @return int
*/
public function getOffset()
{
return $this->pos;
}
}
/**
* Testing fetch function
*
* @param null $array
* @return mixed
*/
function array_fetch_item($array = NULL) {
static $copy;
if ($array) {
$copy = $array;
} else {
return array_shift($copy);
}
}
class TableIterator extends IteratorIterator
{
private $columns;
private $row;
public function __construct(Iterator $it, $columns)
{
$this->columns = $columns;
$this->row = -1;
parent::__construct($it);
}
public function current()
{
$this->row++;
return new PadIterator($this->getInnerIterator(), $this->columns);
}
public function key()
{
return $this->row;
}
public function valid()
{
return $this->getInnerIterator()->valid();
}
}
array_fetch_item(range('A', 'G'));
$it = new FetchIterator('array_fetch_item');
$table = new TableIterator($it, 5);
if ($table->valid()) : ?>
<table border="1">
<?php foreach ($table as $row => $columns) : ?>
<tr class="<?php echo $row % 2 ? 'odd' : 'even'; ?>">
<?php foreach ($columns as $index => $column) : ?>
<td><?php echo $index, ': ', $column; ?> </td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
</table>
<?php endif;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment