Search code examples
phparraysiteratorphp-7php-7.1

PHP iterable to array or Traversable


I'm quite happy that PHP 7.1 introduced the iterable pseudo-type.

Now while this is great when just looping over a parameter of this type, it is unclear to me what to do when you need to pass it to PHP functions that accept just an array or just a Traversable. For instance, if you want to do an array_diff, and your iterable is a Traversable, you will get an array. Conversely, if you call a function that takes an Iterator, you will get an error if the iterable is an array.

Is there something like iterable_to_array (NOT: iterator_to_array) and iterable_to_traversable?

I'm looking for a solution that avoids conditionals in my functions just to take care of this difference, and that does not depend on me defining my own global functions.

Using PHP 7.1


Solution

  • For the "iterable to array" case it seems there is no single function call you can make and that you'll either need to use a conditional in your code or define your own function like this one:

    function iterable_to_array( iterable $iterable ): array {
        if ( is_array( $iterable ) ) {
            return $iterable;
        }
        return iterator_to_array( $iterable );
    }
    

    For the "iterable to Iterator" case things are much more complicated. Arrays can be easily translated into a Traversable using ArrayIterator. Iterator instances can just be returned as they are. That leaves Traversable instances that are not Iterator. On first glance it looks like you can use IteratorIterator, which takes a Traversable. However that class is bugged and does not work properly when giving it an IteratorAggregate that returns a Generator.

    The solution to this problem is too long to post here though I have created a mini-library that contains both conversion functions:

    • function iterable_to_iterator( iterable $iterable ): Iterator
    • function iterable_to_array( iterable $iterable ): array

    See https://github.com/wmde/iterable-functions