PHP RFC: Intersection Types
- Version: 1.0
- Date: 2016-04-27
- Author: Levi Morrison levim@php.net
- Status: Under Discussion
- First Published at: http://wiki.php.net/rfc/intersection_types
Introduction
Sometimes multiple behaviors are necessary for a routine to be able to do its job but there is no common interface for those behaviors. Sometimes a common interface can be extracted, but this is not doable in third-party code. This RFC proposes a way to define types that must satisfy multiple types.
Proposal
Intersection types allow the programmer to write multiple type declarations for a parameter or return value. The value must satisfy all of the declared types. Each type is separated by ampersand (&
).
Here is a practical example. Given this definition:
function RecordsToList(Countable & Traversable $input): String { if (count($input) > 0) { $output = "<ol>\n"; foreach ($input as $value) { $output .= "\t<li>" . htmlentities($value) . "</li>\n"; } $output .= "</ol>\n"; return $output; } else { return "<p>No items to display.</p>\n"; } }
This will error (see on 3v4l.org):
// Argument 1 passed to RecordsToList() must be Countable and Traversable, array given echo RecordsToList(["Lennon", "McCartney", "Starr", "Harrison"]);
This works correctly (see on 3v4l):
echo RecordsToList(new ArrayObject(["Lennon", "McCartney", "Starr", "Harrison"])); // Output: // <ol> // <li>Lennon</li> // <li>McCartney</li> // <li>Starr</li> // <li>Harrison</li> // </ol>
Note that if Union Types are also accepted then something like this will be possible1), allowing for an array or an object that satisfies both Countable and Traversable:
function RecordsToList(Array | (Countable & Traversable) $input): String { if (count($input) > 0) { $output = "<ol>\n"; foreach ($input as $value) { $output .= "\t<li>" . htmlentities($value) . "</li>\n"; } $output .= "</ol>\n"; return $output; } else { return "<p>No items to display.</p>\n"; } }
When union and intersection types are in the same expression they must be grouped with parenthesis (demonstrated above). The following is invalid:
function RecordsToList(Array | Countable & Traversable $input): String { // ... }
Backward Incompatible Changes
There are no known backwards compatibility breaks.
Proposed PHP Version(s)
This feature is proposed for PHP 7.1.
Open Issues
Make sure there are no open issues when the vote starts!
Proposed Voting Choices
This feature will have a simple Yes/No vote requiring two-thirds in the affirmative.
Patches and Tests
A proof of concept patch has been provided by Joe Watkins and Bob Weinand: https://github.com/php/php-src/pull/1887
Note there are multiple features contained in this patch, such as union types.
References
- Original announcement on Mailing List of rationale for this feature: http://news.php.net/php.internals/92252
- Announcement for discussion phase: http://news.php.net/php.internals/92857