rfc:arrayof

PHP RFC: Array Of

  • Version: 0.2.0
  • Date: 2014-01-15
  • Author: Joe Watkins, krakjoe@php.net & Phil Sturgeon philstu@php.net
  • Status: Under Discussion
  • First Published at: http://wiki.php.net/rfc/arrayof

Introduction

This RFC proposes a syntax to add to improve type-hinting, allowing an array of that hinted type to be passed as an argument, thus improving readability of code, improving expectations of passed items, reducing boilerplate code required to check the contents of an array and offering minor performance improvements.

Proposal

Under this proposal, a new syntax is introduced:

function test(SplFileObject[] $files) {
  var_dump($files);
}

The square brackets allow type-hinting for an array where each value is of a specific type. This is handy when simply type-hinting with “array” is just not clear enough what the content should be. It improves readability and self-documentation of the signature, and avoids asking users to foreach through the argument to verify if each item is of the expected type.

Default values can still be used:

function test(SplFileObject[] $files = null) {
    var_dump($files);
}
test(); // Outputs: null

Interfaces and instances work in the same way as expected for existing type-hints:

interface Face {}
 
class One implements Face {}
 
class Two extends One {}
 
class Other {}
 
function test(Face[] $objects) {
    var_dump($objects);
}
 
test('stuff'); // Catchable fatal error: Argument 1 passed to test() must be an array of Face, string given
 
test([new One, new Other]); // Catchable fatal error: Argument 1 passed to test() must be an array of Face, Other found
 
test([new One, new Two]); // Success

While this may look like it contains similarities to the variadic syntax, it is not intended for the same use-case. Variadics hint against the type of multiple parameters, this proposed syntax hints against the type of the contents in one.

Variadic syntax can be used to provide an alternative interface for function usage, or combined to accept an unlimited number of arrays, of which the content will be of a specific type.

function testArrayOf(Face[] $objects) {
    var_dump($objects);
}
testArrayOf([new One, new Two]);
 
// array(2) {
//   [0]=>
//   object(One)#1 (0) {
//   }
//   [1]=>
//   object(Two)#2 (0) {
//   }
// }
 
 
function testVariadics(Face ...$objects) {
    var_dump($objects);
}
testVariadics(new One, new Two);
 
// array(2) {
//   [0]=>
//   object(One)#2 (0) {
//   }
//   [1]=>
//   object(Two)#1 (0) {
//   }
// }
 
function testVariadicArrays(Face[] ...$objects) {
    var_dump($objects);
}
testVariadicArrays([new One, new Two], [new Two]);
 
// array(2) {
//   [0]=>
//   array(2) {
//     [0]=>
//     object(One)#2 (0) {
//     }
//     [1]=>
//     object(Two)#1 (0) {
//     }
//   }
//   [1]=>
//   array(1) {
//     [0]=>
//     object(Two)#3 (0) {
//     }
//   }
// }

The two are by no means mutually exclusive.

A limitation of the variadics feature is that they can only go at the end of a function signature, and there can only be on variadic argument per signature, whilst the “array of” syntax can be used multiple times at any location in the signature.

Unaffected PHP Functionality

This RFC has no effect on variadics, or named parameters. It does not alter other type-hinting rules in regards to what can be hinted against (callable, array, classes, interface, traits, etc) and does not attempt to type-hint against scalar values. This is being taken care of in Scalar Type Hinting with Case

This also does not attempt to allow Traversable or other objects implementing interfaces to be considered an “array”, to match current behavior with hinting for an array.

Closed Questions

1. Should multi-dimensional hints be allowed?

function test(Foo[][] $files = null) {}

The general consensus seemed to be that instead of using “function (ChessPieces[][])” a better solution would probably to simply use “function (Black[] $pieces, White[] $pieces)” instead.

2. RFC suggested syntax, or Hack Generics syntax?

With this features close proximity to the “generics” feature found in other languages - including Java, C# and Hack - the Hack syntax was suggested to replace the syntax in this RFC, which would be the first half of a larger effort in a later version to introduce full-generics. A survey was held to see if people were interested in going down the route of generics and the answer was mostly “Yes, but we want this Array Of too”.

http://grokbase.com/p/php/php-internals/141rva4cf7/php-dev-vote-array-of-v-generics

Java has both features, with their own syntax. This means there is no reason for us to hold off implementing with the existing syntax and looking into adding generics as well, at a later date.

If people want to change the syntax of this feature more in line with Hack generics syntax then simply vote no, and we can revisit the issue.

3. The RFC is currently effectively the same as the code below:

foreach ($foos as $foo) {
    if (! $foo instanceof Face) {
        throw new Exception ('AAAGGGGGHHH!');
    }
}

Some have suggested they would prefer nulls to be allowed in the array, so the syntax would instead represent the following:

foreach ($foos as $foo) {
    if (! is_null($foo) and ! $foo instanceof Face) {
        throw new Exception ('AAAGGGGGHHH!');
    }
}

The downside here is that before anyone can confidently interact with a type array of what one would assume are instances, they need to do a array_filter() first.

Logic here would dictate that if you ask for a bag of spanners, you get a bag of spanners, not a bag with a few spanners and maybe a few “I owe you one spanner” notes.

Multiple people suggested that by default allowing nulls would make this feature useless, and that syntax could be added for the alternative. This syntax can be addressed in a later RFC but could be as simple as function (Foo[]? $foos). Undecided at this point.

Backward Incompatible Changes

None.

Proposed PHP Version(s)

PHP 5.6

Vote

VOTE: 2014/02/28 - 2014/03/07

Array Of Type Hinting
Real name Yes No
aharvey (aharvey)  
ajf (ajf)  
andrey (andrey)  
bwoebi (bwoebi)  
daverandom (daverandom)  
derick (derick)  
fa (fa)  
Fabien Potencier (fabpot)  
guilhermeblanco (guilhermeblanco)  
hradtke (hradtke)  
jpauli (jpauli)  
levim (levim)  
lstrojny (lstrojny)  
mightyuhu (mightyuhu)  
mrook (mrook)  
philstu (philstu)  
rasmus (rasmus)  
rdlowrey (rdlowrey)  
stas (stas)  
treffynnon (treffynnon)  
Count: 4 16

Implementation

Joe Watkins has implemented the feature with some tests. Remaining tests are just to cover exact wording of the error message, which is still open for discussion.

Pull Request

Performance

References

rfc/arrayof.txt · Last modified: 2014/03/16 14:45 by philstu