Typed Arrays in PHP

Typed Arrays in PHP

Even though Rasmus Lerdorf denies the fact, typed arrays exist in PHP. At least to some degree. This wonderful feature sneaked in as a side-effect of variadic functions that were added to the language in PHP 5.6. As you certainly know, PHP functions can receive more arguments than defined as parameters in their signature. An array comprising the full argument list can be obtained using the func_get_args() function. In a nutshell, variadics were introduced to replace func_get_args() and improve access to variable function arguments:

function   foo ( ... $args )
{
     /* ... */
}

Regardless how many arguments have been passed to the function above, they are all accessible as elements of the $args array. This is nothing special really, until you realize that variadics can be augmented with type declarations:

function   foo ( Product   ... $products )
{
     /* ... */
}

So now an array passed to a function can be strictly checked to only contain elements of a specific type. If not, a fatal error will be triggered just like it would in the case of a type mismatch for a regular argument. So from the parameter's point of view it is a typed array! Think about how many input parameter validations can be dropped, how many named constructors can become a thing of the past! How many collection objects whose sole purpose was to carry the set of similar objects will become obsolete.

With the scalar type declarations of PHP 7, the number of possibilities grows:

function   foo ( string   ... $arrayOfStrings )
{
     /* ... */
}

When it comes to passing an array to such a function, another feature introduced in PHP 5.6 comes in handy: argument unpacking can convert the array into list of arguments. The function defined above can be called in the following manner:

foo ( ... $products ) ;

In the example above, $products is an array containing (or not) elements of a required type.

There are two limitations however. Only one variadic is allowed in a function signature and it has to be the last parameter. While the parameters order can hardly be an issue, the limitation of one typed array per function is a bit unpleasant.

It is also possible to check the type of elements while iterating through an array. The way to do it is just to use higher-order functions such as array_map(), array_reduce(), or array_filter(), for instance, instead of the rather procedural foreach statement:

array_map (
     function ( Product   $product )
     {
         /* ... */
     } ,
     $products
) ;

As you can see in the example above, the type declaration for a closure argument will ensure the type of each array element. A mismatch will lead to a fatal error.

Using higher-order functions instead of regular loops can be even nicer from a readability point of view and safer from an immutability standpoint. However this is already a subject for another article.