Last active
August 29, 2015 14:04
-
-
Save mudge/3cda558c73f7ea0f7a16 to your computer and use it in GitHub Desktop.
Fun with PHP's Iterator classes to implement a lazy flat map.
This file contains hidden or 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 | |
/* From https://github.com/guzzle/iterator/blob/master/MapIterator.php */ | |
class MapIterator extends \IteratorIterator | |
{ | |
/** @var mixed Callback */ | |
protected $callback; | |
/** | |
* @param \Traversable $iterator Traversable iterator | |
* @param array|\Closure $callback Callback used for iterating | |
* | |
* @throws InvalidArgumentException if the callback if not callable | |
*/ | |
public function __construct(\Traversable $iterator, $callback) | |
{ | |
parent::__construct($iterator); | |
if (!is_callable($callback)) { | |
throw new InvalidArgumentException('The callback must be callable'); | |
} | |
$this->callback = $callback; | |
} | |
public function current() | |
{ | |
return call_user_func($this->callback, parent::current()); | |
} | |
} | |
class FlatMapIterator extends MapIterator implements RecursiveIterator | |
{ | |
/** | |
* As we will return a RecursiveIterator from our callback, simply return | |
* the current value. | |
*/ | |
public function getChildren() | |
{ | |
return $this->current(); | |
} | |
/** | |
* As above, this will always be true. | |
*/ | |
public function hasChildren() | |
{ | |
return true; | |
} | |
} | |
$fmi = new FlatMapIterator(new ArrayIterator(array(1, 2, 3)), function ($x) { | |
/* In order to use RecursiveIteratorIterator, this must be an implementation of | |
* RecursiveIterator. | |
*/ | |
return new RecursiveArrayIterator(array($x, $x + 1, $x + 2)); | |
}); | |
$ri = new RecursiveIteratorIterator($fmi, RecursiveIteratorIterator::LEAVES_ONLY); | |
/** | |
* Prints: | |
* int(1) | |
* int(2) | |
* int(3) | |
* int(2) | |
* int(3) | |
* int(4) | |
* int(3) | |
* int(4) | |
* int(5) | |
*/ | |
foreach ($ri as $i) { | |
var_dump($i); | |
} | |
/** | |
* You can happily nest FlatMapIterators too... | |
*/ | |
$fmi2 = new FlatMapIterator(new ArrayIterator(array(1, 2, 3)), function ($x) { | |
return new FlatMapIterator(new ArrayIterator(array('a', 'b', 'c')), function ($y) use ($x) { | |
return new RecursiveArrayIterator(array($x, $y)); | |
}); | |
}); | |
$ri2 = new RecursiveIteratorIterator($fmi2, RecursiveIteratorIterator::LEAVES_ONLY); | |
/** | |
* Prints: | |
* int(1) | |
* string(1) "a" | |
* int(1) | |
* string(1) "b" | |
* int(1) | |
* string(1) "c" | |
* int(2) | |
* string(1) "a" | |
* int(2) | |
* string(1) "b" | |
* int(2) | |
* string(1) "c" | |
* int(3) | |
* string(1) "a" | |
* int(3) | |
* string(1) "b" | |
* int(3) | |
* string(1) "c" | |
*/ | |
foreach ($ri2 as $i) { | |
var_dump($i); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment