PHP 7.1: changes to types
September 08, 2016 —Cet article est aussi disponible en français.
This is the 4th post in a series about PHP 7.1.
One of the most important changes PHP 7.0 brought us last year was about typing, with the introduction of scalar type-declarations for functions/methods parameters and their return value.
PHP 7.1 adds to those type-declarations, with several points that were missing in the previous version of the language.
Nullable Types
The type-declaration mechanism was suffering one great limitation in PHP 7.0: we couldn’t declare a parameter could be null
without making it optional at the same time.
For example, with the following function declaration, the second call was invalid, as null
is not an integer:
function fonc01(int $a) {
var_dump($a);
}
fonc01(100); // int(100)
fonc01(null); // TypeError: Argument 1 passed to fonc01() must be of the type integer, null given
Being able to pass null
, often meaning “this is a not-specified value”, was a need expressed a few times when PHP 7.0 was being developed and after its release.
To answer this request, PHP 7.1 introduces nullables types. By positioning a ?
at the beginning of a type’s name, like ?int
, we indicate the null
value is accepted:
function fonc01(?int $a) {
var_dump($a);
}
fonc01(100); // int(100)
fonc01(null); // NULL
Note using a nullable type doesn’t mean the parameter is optional nor it is null
by default: an Error
will still be thrown if an expected parameter has not been given when calling the function:
fonc01();
// Uncaught Error: Too few arguments to function fonc01(), 0 passed
This nullables types idea also works for the return value:
function fonc02(?int $a, ?int $b) : ?int {
if ($a === null || $b === null) {
return null;
}
return $a + $b;
}
var_dump( fonc02(10, 20) ); // int(30)
var_dump( fonc02(10, null) ); // NULL
‣ The RFC: Nullable Types
Void Return Type
In PHP, a function can explicitly return a value, using the return
keyword and that value, or not return any value — either using the return
keyword alone, or simply not using it at all:
function returns_a_value()
{
// This function returns a value
return 42;
}
function returns_nothing()
{
// This function returns null
return;
}
function does_not_return()
{
// This function return null too!
}
Type-declarations, as added to PHP 7.0, allowed us to specify of which type a return value should be, but we couldn’t indicate a function or method must not return anything.
As an answer, PHP 7.1 introduces a new pseudo-type we can use as a return type for a function or method:void
. A function using this pseudo-type cannot return any value. This means these two syntax are valid:
function returns_nothing() : void
{
// This function returns null
return;
}
function does_not_return() : void
{
// This function returns null too
}
These two functions don’t return any value and respect the void
return type-declaration. On the other way, the following function is invalid:
function returns_a_value() : void
{
return 42;
}
Here, we are trying to return a value. This violates the void
type-declaration, so we’ll get a fatal error:
Fatal error: A void function must not return a value in .../demo-03.php on line 16
Note this error occurs during the script’s compilation and not when it’s being executed: PHP detects, as soon as it compiles the code, the return
keyword is used with a value.
‣ The RFC: Void Return Type
Iterable
The third and last addition to PHP’s type-declaration mechanism is a new pseudo-type, called iterable
. It regroups all kind of data on which we can iterate: arrays and traversables data, like iterators (and generators, as a consequence).
This keyword is used as any other type-declaration:
function fonc01(iterable $data) {
foreach ($data as $key => $val) {
var_dump($val);
// ...
}
}
This declaration guarantees we can loop over the received data. For example, we can loop on the content of an array:
fonc01([10, 20, 30]);
In this specific case, we already had the array
type-declaration. But, contrary to iterable
, it didn’t allow us to give an instance of object implementing the Iterator
interface (which, in turns, extends Traversable
):
fonc01(new SplFixedArray(5));
Of course, as a generator is an iterator, we can also use one here:
function my_generator() {
yield 100;
yield 200;
yield 300;
}
fonc01(my_generator());
For an example that doesn’t work, as we cannot loop over a string, the iterable
type-declaration will reject any data of that kind:
fonc01("plop");
// TypeError: Argument 1 passed to fonc01() must be iterable, string given
With this new pseudo-type, PHP 7.1 has an answer to a frequently expressed need: being able to specify an iterable piece of data is expected, but accepting both an array or an object implementing Traversable
.
‣ The RFC: Iterable