PHP RFC: Iterable
- Version: 0.1.1
- Date: 2016-06-10
- Author: Aaron Piotrowski aaron@trowski.com
- Status: Implemented in PHP 7.1
- First Published at: http://wiki.php.net/rfc/iterable
Introduction
It is common for a function to accept or return either an array
or an object implementing Traversable
to be used with foreach
. However, because array
is a primitive type and Traversable
is an interface, there currently is no way to use a type declaration on a parameter or return type to indicate that the value is iterable.
Proposal
This RFC proposes a new iterable
pseduo-type. This type is analogous to callable
, accepting multiple types instead of one single type.
iterable
accepts any array
or object implementing Traversable
. Both of these types are iterable using foreach and can be used with yield from
within a generator.
iterable
can be used as a parameter type to indicate that a function requires a set of values, but does not care about the form of the value set (array
, Iterator
, Generator
, etc.) since it will be used with foreach
. If a value is not an array or instance of Traversable
, a TypeError
will be thrown.
function foo(iterable $iterable) { foreach ($iterable as $value) { // ... } }
iterable
can also be used as a return type to indicate a function will return an iterable value. If the returned value is not an array or instance of Traversable
, a TypeError
will be thrown.
function bar(): iterable { return [1, 2, 3]; }
Parameters declared as iterable
may use null
or an array as a default value.
function foo(iterable $iterable = []) { // ... }
Functions declaring iterable
as a return type may also be generators.
function gen(): iterable { yield 1; yield 2; yield 3; }
Classes extending/implementing may broaden methods using array
or Traversable
as parameter types to iterable
or narrow return types from iterable
to array
or Traversable
. This behavior is the same as that proposed for all union types in the Union Types RFC.
interface Example { public function method(array $array): iterable; } class ExampleImplementation implements Example { public function method(iterable $iterable): array { // Parameter broadened and return narrowed. } }
This proposal also adds a function is_iterable()
that returns a boolean: true
if a value is iterable and will be accepted by the iterable
pseudo-type, false
for other values.
var_dump(is_iterable([1, 2, 3])); // bool(true) var_dump(is_iterable(new ArrayIterator([1, 2, 3]))); // bool(true) var_dump(is_iterable((function () { yield 1; })())); // bool(true) var_dump(is_iterable(1)); // bool(false) var_dump(is_iterable(new stdClass())); // bool(false)
Object Iteration
PHP allows any object to be used with foreach
. However, iterable
does not accept any object, only those implementing Traversable
. Values accepted by iterable
should be designed for iteration, not any set of values (such as the public properties of an object or a string). There is already some precedent in the language for discriminating between values accepted by iterable
and those that can be used with foreach
. yield from
only accepts arrays or objects implementing Traversable
. iterable
then represents the values usable with yield from
.
Backward Incompatible Changes
iterable
is implemented as reserved classname, therefore a class, interface, or trait named iterable
cannot be declared.
Another function named is_iterable()
cannot be declared in the root namespace.
Proposed PHP Version(s)
PHP 7.1
Future Scope
Union Types
If the union types RFC is accepted, then iterable
will be a shortcut for array | Traversable
. This is a common type requirement for functions, so having a shorter name for this union will be handy.
Voting
This proposal requires a 2/3 majority to be accepted.
Voting began on 2016-06-24 at 6:00 pm GMT and ended on 2016-07-02 at 11:59 pm GMT
Patches and Tests
PR: #1941