Skip to content

Instantly share code, notes, and snippets.

@dhrrgn
Created August 1, 2013 15:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dhrrgn/6132705 to your computer and use it in GitHub Desktop.
Save dhrrgn/6132705 to your computer and use it in GitHub Desktop.
(WIP) Functions creating iterators for looping, based off the python itertools module.
<?php
/**
* Functions creating iterators for looping, based off the python itertools
* module.
*
* @author Dan Horrigan <dan@dhorrigan.com>
* @license MIT License
* @copyright 2013 Daniel Horrigan
*/
namespace iter;
use InvalidArgumentException;
/**
* A Generator which iterators through all the elements of all the arguments
* in order until all items have been iterated over.
*
* Example:
*
* foreach (chain(str_split('ABC'), str_split('DEF')) as $c) {
* echo $c." ";
* }
* // Output: A B C D E F
*
* @return Iterator
*/
function chain()
{
foreach (func_get_args() as $v) {
if ( ! _is_traversable($v)) {
throw new InvalidArgumentException("Value '{$v}', must be traversable.");
}
foreach ($v as $elem) {
yield $elem;
}
}
}
/**
* A simple counter Generator. It will start at the given number and add `step`
* to it infinitely.
*
* @param integer $start The number to start at.
* @param integer $step The amount to increase by each iteration.
* @return Iterator
*/
function counter($start = 0, $step = 1)
{
$i = $start;
while (true) {
yield $i;
$i += $step;
}
}
/**
* A generator that infinetly cycles through the given values. You can send
* either an array of values, or send the values as arguments.
*
* @param mixed $values If an array and the only argument, it is iterated over.
* @return Iterator
*/
function cycle($values)
{
if (func_num_args() > 1 || ! _acts_as_array($values)) {
$values = func_get_args();
}
$i = 0;
$len = count($values);
while (true) {
if ($i === $len) {
$i = 0;
}
yield $values[$i];
$i++;
}
}
/**
* The same as the PHP `range()` function, except implemented with an iterator.
*
* @param integer $start First value of the sequence.
* @param integer $end The value to end the sequence at.
* @param integer $step Amount to increment with each iteration.
* @return Iterator
*/
function xrange($start, $end, $step = 1)
{
foreach (counter($start, $step) as $i) {
yield $i;
if ($i === $end) {
break;
}
}
}
/**
* Repeats the given item either infinitly or the given amount of times.
*
* @param mixed $item The item to repeat.
* @param integer $times The number of times to repeat (null for inf)
* @return Iterator
*/
function repeat($item, $times = null)
{
if (is_null($times)) {
while (true) {
yield $item;
}
} else {
for ($i = 0; $i < $times; $i++) {
yield $i;
}
}
}
/**
* Checks if the given value can be traversed using a foreach loop.
*
* @param mixed $value The value to check.
* @return boolean
*/
function _is_traversable($value)
{
return is_array($value) || is_a($value, 'Traversable');
}
/**
* Checks if the given value can be accessed like an array.
*
* @param mixed $value The value to check
* @return boolean
*/
function _acts_as_array($value)
{
return is_array($value) || (is_a($value, 'ArrayAccess') && is_a($value, 'Countable'));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment