Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 536
Jeroen De Dauw Avatar asked Jun 16 '17 11:06

Jeroen De Dauw


People also ask

What is traversable PHP?

The Traversable interface ¶Abstract base interface that cannot be implemented alone. Instead it must be implemented by either IteratorAggregate or Iterator. Note: Internal (built-in) classes that implement this interface can be used in a foreach construct and do not need to implement IteratorAggregate or Iterator.

What is the use of Iterable in PHP?

An iterable is any value which can be looped through with a foreach() loop. The iterable pseudo-type was introduced in PHP 7.1, and it can be used as a data type for function arguments and function return values.

What is iterable return type?

Iterable<T> is an interface. What this means is that when you receive it as a return value from a method, you actually receive an implementation of it.


4 Answers

Not sure this is what are you searching for but this is the shortest way to do it.

$array = [];
array_push ($array, ...$iterable);

I'm not very sure why it works. Just I found your question interesting and I start fiddling with PHP

Full example:

<?php

function some_array(): iterable {
    return [1, 2, 3];
}

function some_generator(): iterable {
    yield 1;
    yield 2;
    yield 3;
}

function foo(iterable $iterable) {
    $array = [];
    array_push ($array, ...$iterable);
    var_dump($array);

}

foo(some_array());
foo(some_generator());

It would be nice if works with function array(), but because it is a language construct is a bit special. It also doesn't preserve keys in assoc arrays.

like image 90
Edwin Rodríguez Avatar answered Sep 28 '22 04:09

Edwin Rodríguez


Is there something like iterable_to_array and iterable_to_traversable

Just add these to your project somewhere, they don't take up a lot of space and give you the exact APIs you asked for.

function iterable_to_array(iterable $it): array {
    if (is_array($it)) return $it;
    $ret = [];
    array_push($ret, ...$it);
    return $ret;
}

function iterable_to_traversable(iterable $it): Traversable {
    yield from $it;
}
like image 40
Sara Avatar answered Sep 20 '22 13:09

Sara


For php >= 7.4 this works pretty well out of the box:

$array = array(...$iterable);

See https://3v4l.org/L3JNH

Edit: Works only as long the iterable doesn't contain string keys

like image 8
Michael Petri Avatar answered Sep 28 '22 04:09

Michael Petri


Can be done like this:

$array = $iterable instanceof \Traversable ? iterator_to_array($iterable) : (array)$iterable;
like image 7
alexkart Avatar answered Sep 28 '22 05:09

alexkart