What’s New and Exciting in PHP 7.1?
This article was peer reviewed by Thomas Punt. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!
The PHP community has gone viral with the latest PHP 7 announcement and all the goodies it brings to the language. The PHP 7.1 release has more good news and features to offer. This article highlights the most important ones, and you should check PHP RFC for the full list.
ArgumentCountError Exception
Earlier versions of PHP allowed for function calls with fewer arguments than specified, emitting a warning when you have a missing argument.
// PHP 5.6
function sum($a, $b)
{
return $a + $b;
}
sum();
// Warning: Missing argument 1 for sum()
// Warning: Missing argument 2 for sum()
sum(3);
// Warning: Missing argument 2 for sum()
sum(3, 4);
Warnings are not useful for this case, and the developer should check if all arguments are set correctly. In PHP 7.1, those warnings have been converted into an ArgumentCountError
exception.
// PHP 7.1
function sum($a, $b)
{
return $a + $b;
}
sum();
// Fatal error: Uncaught ArgumentCountError: Too few arguments to function sum(), 0 passed in /vagrant/index.php on line 18 and exactly 2 expected in /vagrant/index.php:13
sum(3); // skipped
sum(3, 4); // skipped
Nullable Types
PHP 7 added type declarations for parameters and return types, but it seemed that something was missing! Nullable types enable for the specified type to take either that type or null. Here’s an example:
function sum(int $a, int $b): ?int
{
return $a + $b;
}
The above function may return an integer or a null value, so if something wrong happens in the function’s logic you won’t be returning null as the wrong type. You can do the same for arguments, too!
function sum(?int $a, ?int $b): ?int
{
if ($a == null || $b == null) {
return null;
}
return $a + $b;
}
The unexpected thing is that calling the function without arguments will throw an exception!
var_dump(sum(null, null)); // NULL
var_dump(sum()); // throw ArgumentCountError exception
This means that you should explicitly specify arguments when they don’t have a default value.
Another thing you should keep in mind is that when overriding or implementing methods, you can’t add the nullable type to the return type, but you’re allowed to remove it. And the reverse is true for arguments, you can’t remove the nullable type from arguments, but you’re allowed to add it!
interface Fooable {
function foo(): ?Fooable;
}
interface StrictFooable extends Fooable {
function foo(): Fooable; // valid
}
interface Fooable {
function foo(): Fooable;
}
interface LooseFooable extends Fooable {
function foo(): ?Fooable; // invalid
}
Destructuring Arrays
We used to do the following when destructuring arrays.
list($a, $b, $c) = [1, 2, 3];
var_dump($a, $b, $c); // int(1) int(2) int(3)
But trying this would fail, because we couldn’t specify keys to extract and the function tried to use index keys.
list($a, $b, $c) = ["a" => 1, "b" => 2, "c" => 3];
var_dump($a, $b, $c); // NULL NULL NULL
This RFC provides more control over array destructuring. The above code could be changed to this.
list("a" => $a, "b" => $b, "c" => $c) = ["a" => 1, "b" => 2, "c" => 3];
var_dump($a, $b, $c); // int(1) int(2) int(3)
The list
function now accepts keys for array destructuring, and because this is used a lot, a new compact syntax has been introduced. Take this as an example.
["a" => $a, "b" => $b, "c" => $c] = ["a" => 1, "b" => 2, "c" => 3];
var_dump($a, $b, $c); // int(1) int(2) int(3)
Cool, isn’t it? And it also works on multidimensional arrays.
[[$a, $b], [$c, $d]] = [[1, 2], [3, 4]];
var_dump($a, $b, $c, $d); // int(1) int(2) int(3) int(4)
[["b" => $b], ["c" => $c]] = [["a" => 1, "b" => 2], ["c" => 3, "d" => 4]];
var_dump($b, $c); // int(2) int(3)
Iterable Type
The iterable
pseudo-type is added to join the array primitive type and the Traversable
interface which is used to make a value iterable. Take the below code as an example.
// PHP 5.6
function dump(array $items)
{
var_dump($items);
}
dump([2, 3, 4]);
dump(new Collection());
array(3) {
[0]=>
int(2)
[1]=>
int(3)
[2]=>
int(4)
}
Catchable fatal error: Argument 1 passed to dump() must be of the type array, object given...
But in this case, the function won’t accept an iterable value and will throw an error. This new change lets you use iterable
to describe an iterable value instead of asserting it manually.
// PHP 7.1
function dump(iterable $items)
{
var_dump($items);
}
dump([2, 3, 4]);
dump(new Collection());
array(3) {
[0]=>
int(2)
[1]=>
int(3)
[2]=>
int(4)
}
object(Collection)#2 (0) {
}
Closure From Callable Function
The new fromCallable
method provides a performant and compact way of creating Closure objects from callables. Here’s an example:
$callback = Closure::fromCallable([$this, 'fn']);
Void Return Type
This is one of my favorite new features. It completes the return types feature introduced in PHP 7 where functions may not return anything and thus will be forced to return null!
function dump($object): void
{
var_dump($object);
}
A void function can omit the return statement or add an empty one (return;
).
Class Constant Visibility
This is a small change, but an essential part in OOP that enforces encapsulation. It adds visibility modifiers to class constants.
class Post
{
protected const PUBLISHED = 1;
protected const DRAFT = 2;
protected const TRASHED = 3;
// ...
}
Catching Multiple Exception Types
Other languages like Java provide the ability to catch multiple exception types inside the same catch block, thus removing the need to duplicate code. Take the below code as an example:
// ...
try {
$user->payMonth($month);
} catch (UserSuspendedException $ex) {
DB::rollBack();
return redirect()
->back()
->withInput()
->withErrors([$ex->getMessage()]);
} catch (PaidMonthException $e) {
DB::rollBack();
return redirect()
->back()
->withInput()
->withErrors([$ex->getMessage()]);
}
// ...
You can remove the duplication by using the new catch block syntax:
// ...
try {
$user->payMonth($month);
} catch (PaidMonthException | UserSuspendedException $ex) {
DB::rollBack();
return redirect()
->back()
->withInput()
->withErrors([$ex->getMessage()]);
}
// ...
Invalid String Arithmetics
As you start learning PHP, you get an aha moment when doing arithmetics and you learn that strings are allowed! This is because PHP usually deals with the web and values are coming in as strings.
// PHP 5.6
var_dump("1" + "2");
var_dump("1" + "a string");
var_dump("1" + "2 with a string");
int(3)
int(1)
int(3)
// PHP 7.1
var_dump("1" + "2");
var_dump("1" + "a string");
var_dump("1" + "2 with a string");
int(3)
Warning: A non-numeric value encountered in /vagrant/index.php on line 17
int(1)
Notice: A non well formed numeric value encountered in /vagrant/index.php on line 18
int(3)
Now we get a warning if a non numeric value is found, and a notice if the value is not well formatted (2 a string
= 2
).
Conclusion
This list does not cover all the new changes, so be sure to check the RFC list for the full list. If you have a question or comment about the new PHP 7.1 features or PHP in general, please post them below!