I recently posted a blog on why I think you should use Generators instead of arrays. In this post I mentioned the caveat that Generators, and by extension any Traversable, could not be used in conjunction with array_ functions. This is kind of a bummer, because those functions are very handy. And it got me thinking: why shouldn't these functions exist? So here they are.

How to use Iterator Functions

The package provides 8 functions to help with Iterators. Let's look at two examples. First off, iterator_map().

I use array_map() all the time. It's a handy way of quickly changing all values of an array into something else, by applying a callback function on it. The downside of this is memory consumption. You transform the entire array at once. Only after that can you use, or traverse, every new item in the array.

When using iterator_map() you get the best of both worlds. The ease of use of an array_-like function, and the added benefit of less memory consumption. This is because the callback is applied while traversing the iterator. Meaning only that value is in memory at that time. As an added bonus: iterator_map() allows for iterable types to be passed. That means an array is also allowed. So even with the use of an array you get the memory preserving benefits!

$ids_iterator = new ArrayIterator([1, 2, 3]);
$ids_array = [4, 5, 6];
 
$mapped_iterator = iterator_map(function(int $id): Model {
return Model::find($id);
}, $ids_iterator, $ids_array);
 
foreach ($mapped_iterator as $model) {
// Here the callback is applied, and the model is returned.
}

In this example we iterate over the values 1 through 6, and retrieve the corresponding Model instance.

Another example is iterator_reduce(). You can use the array_reduce() function to flatten an array into a single new value by applying a callback on every iteration. This callback also receives the previous value. The last iteration effectively decides what the final output will be. iterator_reduce() does the same thing, but with an Iterator.

As an added bonus, and unlike array_reduce(), the callback of iterator_reduce() also receives the key of the current iteration.

$iterator = new ArrayIterator(['name' => 'Doeke Norg', 'age' => 33]);
 
$output = iterator_reduce($iterator, function($carry, $value, string $key): string {
return str_replace('%' . $key . '%', $value, $carry);
}, 'My name is: %name%. I am %age% years old.');
 
// $output = My name is: Doeke Norg. I am 33 years old.

This is a rather silly example, but it's only to get the point across. We change the initial value, which is provided by the 3rd parameter, and replace the key of the current iteration with the value. So the string is actually changed twice; first to replace the name, and second to replace the age.

Try it out

I'd love for you to try out doekenorg/iterator-functions. Besides the obvious helper functions, I added a few extra Iterator types that can be useful. Most of the functions actually use these iterators to preform their task.

If you have any feedback please let me know!