-
-
Save nonsensecreativity/3710939b2bb07167b27e804413241556 to your computer and use it in GitHub Desktop.
Some Iterator Fun
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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