rfc:arrayof

This is an old revision of the document!


PHP RFC: Array Of

  • Version: 0.1.1
  • 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 forech through the argument to calculate 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.

Open Questions

1. 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.

2. Should multi-dimensional hints be allowed?

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

This suggests that array(array(new Foo)) is an acceptable value. I am not sure how useful that is, as you should probably calm down on your nested array structure a little bit and maybe require an object, or split it into multiple parameters.

One example provided has been “function (ChessPieces[][])”. This would probably be better off as “function (Black[] $pieces, White[] $pieces)”.

Backward Incompatible Changes

None.

Proposed PHP Version(s)

PHP 5.6

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.1389821940.txt.gz · Last modified: 2017/09/22 13:28 (external edit)