Skip to content

Instantly share code, notes, and snippets.

@Danack
Last active June 2, 2016 00:36
Show Gist options
  • Save Danack/17d798e6280964b5243877f20679c9bc to your computer and use it in GitHub Desktop.
Save Danack/17d798e6280964b5243877f20679c9bc to your computer and use it in GitHub Desktop.
union

Introduction

In PHP using 'type-hints' to define either the allowed parameter types for a function, or the return type of a function, performs two useful roles:

  1. Using types allows the PHP engine to enforce the correct type of variable are passed to, or returned from, a function.
  2. Using types makes it easy to reason about what types need to be passed to, or can be returned from a function. This makes it easier for both humans, and static code analysis tools, to determine about whether code is correct or not.

For a lot of functions in PHP, each parameter will only be one type. Similarly, for the majority of functions, the return value of a function, will only ever be of one type.

However, for a significant number of functions, the acceptable parameters, or the possible return values, can be of more than one type. For example consider the 'stripos' function where the return value varies based on:

  • if the needle exists it returns an integer.
  • if the needle is not found, a boolean of value false is returned.

In the documentation on php.net, the two possible return types are documented as 'mixed' - however this does not actually document what the possible return types are, only that there is more than one possible type returned. Also, it is not possible to define a 'mixed' type in PHP code.

Currently in userland code, when a parameter for a function can be one of a multiple but limited set of types, or the return value from a function can be one of a multiple but limited set of types, there can be no type information supplied, and so it is not possible for the PHP engine to enforce any types passed to/from that function, and it is not easy for people using that function to reason about the types passed to/from that function.

This RFC seeks to address this limitation.

Proposal

This RFC proposes the ability to define multiple possible types for parameter and return types. To define a 'union type' a single vertical bar (OR) is placed between types e.g. 'int|bool' represents the union type of either integer or boolean. For these 'union types' a value passes the type check if the value would pass any one of the types in the union.

Additionally this RFC proposes that the values 'true', 'false' and 'null' will be usable as types in both parameter types and return type definitions.

There can be more than two types in the union.

Parameter type examples

A function that requires either a string or an array is passed to it as the parameter:

function print_each(array | string $in) {
    foreach ((array) $in as $value) {
        echo $value, PHP_EOL;
    }
}
 
print_each(['Bob', 'Joe', 'Levi']); // ok
print_each('Levi'); // ok
print_each(new stdclass()); // not ok

A class instance method that requires that either a string or a ParameterGenerator object is passed as the parameter.

//From zend-code
class MethodGenerator extends AbstractMemberGenerator
{
     ...
    public function setParameter(ParameterGenerator|string $parameter) {
        ...
    }
}

Return type example

A userland definition of stripos function:

function stripos(string $haystack, string $needle, int $offset = 0): int|bool
{
   $lowerHaystack = strtolower($haystack);
   $lowerNeedle = strtolower($needle);
   return strpos($lowerHaystack, $lowerNeedle, $offset);
}

Patches and Tests

Bob Weinand and Joe Watkins have made a patch: php/php-src#1887 which is needs some small polishing but implements the proposed features.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment