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
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.
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.
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.
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.
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;
}
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
Can be done like this:
$array = $iterable instanceof \Traversable ? iterator_to_array($iterable) : (array)$iterable;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With