Introduction
If you have not read yet our blog post about new features in PHP7, we highly recommend to do so before continue reading.
In this post we’re going to analyze new features proposed by PHP7.1 that have “seen the light” 2 October 2017.
Nullable types
Function’s argument type and return type can be marked as null. You can declare types as nullable by prefixing a question mark ?
before argument/return type.
1 2 3 4 5 6 7 8 9 |
function foo(?Bar $bar) { // You can pass both Bar object and null } function foo(): ?Bar { // You can return both Bar object and null } |
Speaking of argument type we would like to highlight the differences (and similarities) between the following two methods
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function foo(?Bar $bar) { // ... } function bar(Foo $foo = null) { // ... } foo(new Bar()); // ok foo(null); // ok foo(); // Uncaught Error: Too few arguments to function bar(new Foo()); // ok bar(null); // ok bar(); // ok; same as $this->bar(null) |
With this feature you can distinguish between mandatory argument that can be null (foo
function) and optional ones (bar
function). I’ve tried to think about this difference and how it enhances language strength. What I figured out can be resumed in two points:
1. No difference for your API (method) internals
1 2 3 4 5 |
if ($argument === null) { } if ($argument !== null) { } |
Before using $argument
you probably need to check its type in one case or the other, so you don’t get any advantage in using one form or other. However it’s true that API must “communicate” something to those who use it.
2. Semantics
It’s – in a kind of way – a consequence of last sentence at point one, explained above. For a client could be important to know when an attribute it’s mandatory and can be null or when it is simply optional.
Speaking now about returning null, our only suggestion is to NEVER return null
from your functions. When you return null
from a function you can run into this
1 2 3 4 5 6 7 |
function getBar() : ?Bar { return $this->canReturnBar() ? new Bar() : null; } $bar = getBar(); $bar->dummy(); // Uncaught Error: Call to a member function dummy() on null |
Because sometimes you simply forget to check return type.
Basically you’re creating extra-checking work for yourself: you need to implement ad-hoc error handling, your code quickly become dirty, possibly your method name (that should have no lack of intent) should be modified as getBarOrNull
and so on
1 2 3 4 5 6 7 8 9 |
if ($bar instanceof Bar) { $bar->dummy(); } // or if ($bar !== null) { $bar->dummy(); } |
One solution is to use Null Object pattern. For instance if you’re returning an array, return an empty array instead of null.
Another solution is to throw an exception that can either be caught immediately or go up through calling stack. Exceptions have more semantics than a general “Uncaught Error” and can lead to a cleaner code.
Void functions
If your function has only side effects probably you’ll never return anything from your function. From PHP7.1 you can take advantage of this behavior – that is pretty common in other programming languages – specifying void
as function return type
1 2 3 |
function foo() : void { } |
Symmetric array destructuring
You probably know list()
syntax that allows you to “consume” array elements in one statement
1 2 3 4 5 6 |
$arr = [1,2,3]; list($foo, $bar, $foobar) = $arr; echo $foo; // 1; echo $bar; // 2; echo $foobar; // 3; |
With PHP7.1 you can use this equivalent (but more readable to me) syntax
1 2 3 4 5 6 |
$arr = [1,2,3]; [$foo, $bar, $foobar] = $arr; echo $foo; // 1; echo $bar; // 2; echo $foobar; // 3; |
However in PHP <= 7 this “destruction” would have worked only with non-associative array with ordered and consecutive keys
1 2 3 4 5 6 |
$dummy = ['foo' => 'foo', 'bar' => 'bar']; list ($foo, $bar) = $dummy; // Undefined offset: 0; Undefined offset: 1 $dummy = ['foo', 'bar', 'foobar']; unset($dummy[0]); list ($foo, $bar) = $dummy; // Undefined offset: 0 |
PHP7.1 offers a syntax to destruct even associative arrays or ones that does not have consecutive keys
1 2 3 4 5 6 7 8 9 |
$dummy = ['foo' => 'foo', 'bar' => 'bar']; list ('foo' => $foo, 'bar' => $bar) = $dummy; // OK ['foo' => $foo, 'bar' => $bar] = $dummy; // OK $dummy = ['foo', 'bar', 'foobar']; unset($dummy[0]); list (1 => $bar, 2 => $foobar) = $dummy; // OK [1 => $bar, 2 => $foobar] = $dummy; // OK |
Class constant visibility
Now you can specify the visibility for your constants like you do with variables (private, protected, public)
String negative offset
It can be possible to use negative index to access strings and with string manipulation functions
1 2 3 |
$foo = 'My foo string!" echo $foo[-3]; // 'n' echo strpos($foo, 'o', -9); // 5 instead of 4 |
Reference
If you need the whole list of new features you can visit PHP official manual page