====== PHP RFC: Iterable ====== * Version: 0.1.1 * Date: 2016-06-10 * Author: Aaron Piotrowski * 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|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 * Yes * No ===== Patches and Tests ===== PR: [[https://github.com/php/php-src/pull/1941|#1941]]