7 New Features in PHP 7.1

Warning: this is quite a long post!

It seems like yesterday that PHP 7 was unleashed into the world bringing huge changes in its engine as well as a whole load of new language features.

According to W3 Tech, the uptake of PHP 7 has been steadily increasing and has just crossed the 2% mark of all PHP. However, PHP 5.3 and 5.4 use is continuing to plummet and even 5.5 has started to drop since support for ended in the summer. Meanwhile 5.6 has been growing massively these past 5 months.

With 5.6 getting security updates until the end of 2018, people are clearly making this transition before making that the jump to 7. In my opinion, I think if you get your code to 5.6, then you may as well go all the way to 7. However, it is a welcome sight to see 5.3 and 5.4 finally start to die out.

Despite all this, development on PHP has pressed on and it is that time of year again when a new release arrives. 7.1 builds on some of the language features introduced in 7.0 whilst introducing some new things that have been long overdue. Here are 7 new features that I think are notable in this next release. I have linked to the associated RFC for each feature that goes into more detail.

Changes to Return Types

PHP 7 brought the ability to add return types to functions. This allowed developers to be more disciplined and be able to write cleaner code by knowing what types are being returned. PHP 7.1 adds 2 new changes to this feature.

1) Nullable Types

RFC

Here is a very simple function.

function getItem($id) : string
{
    $animals = array("cat", "dog", "hamster", "rabbit");
    $item = null;
    if (isset($animals[$id])) {
        $item = $animals[$id];
    }
    return $item;
}

It uses the return type syntax introduced in PHP 7 and says that this function must return a string.

If I do:

var_dump(getItem(1));

I get string(3) "dog". A string is returned which satisfies the return type of the function.

Now if I was to do:

var_dump(getItem(5));

I get an error:

PHP Fatal error:  Uncaught TypeError: Return value of getItem() must be of the type string, null returned

Obviously. In PHP 7.0, this would have to be dealt with by not returning NULL. But what if we really want to return null sometimes, for example, when getting objects?

Well, PHP 7.1 provides a new syntax to types for exactly this purpose. Below, is the same function again. This time, you can see the return type is ?string.

function getItem($id) : ?string
{
    $animals = array("cat", "dog", "hamster", "rabbit");
    $item = null;
    if (isset($animals[$id])) {
        $item = $animals[$id];
    }
    return $item;
}

This is saying that getItem returns a string or null. So if I now run

 var_dump(getItem(5));

I get NULL.

This syntax can also be applied to parameters passed into functions. Note that this is different from defaulting the parameter to null as demonstrated in the following example:

 function getNumberOfChars($string = null) 
 {
       $numberOfChars = 0;
       if (!is_null($string)) {
            $numberOfChars = strlen($string);
       }
       return $numberofChars;
 }

With the above function, the following calls are valid:

getNumberOfChars("dog");
getNumberOfChars(null);
getNumberOfChars();

Note the last one. This means the parameter is optional. If I changed the function to:

  function getNumberOfChars(?string $string)

Then getNumberOfChars() with no parameters would now be invalid (but the first two calls would be valid).

2) Void Return Types

RFC

Anyone who has coded with a language such as Java will be familiar with the void keyword. This is a special type that indicates that the function with return nothing.

In the interest of starting be stricter with typing, this is a very useful addition to the existing typing system that was introduced in 7.0. It is used simply like so:

function doSomethingRandom() : void
{
    rand(0,10) * rand(0,10);
}
doSomethingRandom();

As you can see, you just use void where you would put a type. If you tried to return something you will get a Fatal Exception such as:

PHP Fatal error: A void function must not return a value.

Returning null will also throw an exception as it still counts as returning "something", however, this is perfectly valid:

function returnNull() : void
{
    return;
}
Changes to list()
3) Using Keys in list()

RFC

Right now, you can use list() like so:

$animals = array("cat", "dog", "hamster", "rabbit");
list($animal1, $animal2, $animal3, $animal4) = $animals;

print $animal1."\n";
print $animal2."\n";
print $animal3."\n";
print $animal4."\n";

This would print:

cat
dog
hamster
rabbit

Essentially, the contents of the array each get assigned to a parameter inside list from left to right starting from index 0 in the array.

But this only works for numeric arrays. Well, PHP 7.1 introduces a new feature that allows you to assign keys in the list. This works like so:

 $animals = array("feline" => "cat", "canine" => "dog", "cricetine" => "hamster", "leporine" => "rabbit");

list("cricetine" => $animal1, "feline" => $animal2, "leporine" => $animal3, "canine" => $animal4) = $animals;

print $animal1."\n";
print $animal2."\n";
print $animal3."\n";
print $animal4."\n";

So the parameters of list() can now be key-value pairs where the key is the key of the array being deconstructed and the value is the array as before.

The above would output:

hamster
cat
rabbit
dog

I purposely changed the order in list to demonstrate that it is using the keys. The following would also produce the same result:

$animals = array("cat", "dog", "hamster", "rabbit");

list(2 => $animal1, 0 => $animal2, 3 => $animal3, 1 => $animal4) = $animals;

That is, you can use the indexes of a numeric array to change the order of assignment!

4) Shorter Syntax for list()

RFC

If you are a fan of shorter and cleaner code then you will like this one. As of 7.1, instead of using list(), you can use a shorter syntax with just square brackets, []. For example:

$animals = array("cat", "dog", "hamster", "rabbit");

[2 => $animal1, 0 => $animal2, 3 => $animal3, 1 => $animal4] = $animals;

Will have the same result as the last example. It will also work for the original "non-key" usage of list().

Other Stuff
5) Multiple Catches

RFC

If you have a try-catch that has multiple catches that catches multiple Exceptions, then you may have had a situation where 2 or more of the Exceptions require the exact same code and you have had to repeat it twice.

Well now, you will be able to catch multiple Exceptions within the same block.

Take the following example:

I have declared two Exception classes:

 class CustomException extends Exception{}

 class AnotherException extends Exception{}

They don't do anything that is different, but this is just for demonstration.
Now, I will make a class that throws either of these Exceptions:

function throwException()
{
    $i = rand(0,1);
    if ($i === 0) {
        throw new CustomException;
    } else {
        throw new AnotherException;
    }
}

Pretty useless function, but it randomly throws one of 2 different Exceptions.

Up to PHP 7.0, to run this function and deal with the multiple Exceptions, you would have to do something like:

try {
    throwException();
} catch (CustomException $e) {
    print "there was an error\n";
} catch (AnotherException $e) {
    print "there was an error\n";
}

Now this is fine if you want to do completely different actions for each Exception, but if, as in the case above, the code is exactly the same, then it is messy and even if you put the repeated code into a function, you still have to repeat the call to that function multiple times.

In PHP 7.1, you can now write the above code like this:

try {
    throwException();
} catch (CustomException | AnotherException $e) {
    print "there was an error\n";
}

Both Exceptions can be caught in the same catch block and whichever one is caught is assigned to the variable as it was before. I think this a great addition to the try-catch syntax. With finally introduced in PHP 5.5, I can't imagine how messy try-catches were in 5.4 and below!

6) Constant Visibility

RFC

A fairly simple feature but one I think will be very useful. Currently, constants are public by default and can only be public:

class MyClass
{
    const SOME_CONSTANT = 10;
}
$class = new MyClass;
var_dump($class::SOME_CONSTANT);

Results in int(10).

As of PHP 7.1, you will be able to specify the visibility of a constant in the same way that you can a variable, using public, private and protected:

class MyClass
{
    private const SOME_CONSTANT = 10;
}

$class = new MyClass;
var_dump($class::SOME_CONSTANT);

Results in Fatal error: Uncaught Error: Cannot access private const MyClass::SOME_CONSTANT.

Don't worry, constants are still public by default so backwards compatibility is maintained.

7) Death of MCrypt

RFC

I have included this one because is it is one of these things that you might not realise that effects you.

In PHP 7.1, MCrypt is deprecated, with the view of removing it completely in whatever version is next. There are several reasons for this explained in the RFC but ultimately, libmcrypt has not been updated since 2007 and so any problems it has are unlikely to ever be fixed!

The suggestion is to use OpenSSl instead. So if you are using MCrypt, you should migrate to this or something else as soon as possible as it will be a required step if you wish to upgrade to a future version when it is removed.

Summary

So there you have it. Just a selection of the many features added to PHP in PHP 7.1. You can find a full complete list here.

I have posted all of the code samples used in this post on a gist.

Sorry for the longer than usual post, but there was a lot to cover. I hope you learnt something, even if, at the very least, it was simply the words "cricetine" and "leporine" (just so you know, you can find animal adjectives for most animals here).


© 2012-2017