PHP 7.4 - 6 Compelling New Features Graded

January 07, 2020
Written by

PHP 7.4 - 6 Compelling Features Graded

PHP 7.4 has arrived, and it's shipped the usual raft of exciting features and improvements. For a recent live stream, we looked at all the features in the release notes and figured out what each one means in a coding sense. Let's take a look at some of the new features in PHP 7.4, and grade each one from A-F depending on how interesting they are, and my excitement to use them.

Note: This is my personal opinion based on my own unique experiences and opinions. You'll probably disagree with some of my grades, and that's good. Your opinions and experiences are different from mine. Let me know in the comments or on Twitter where you feel I went wrong.

Typed Properties

We've been waiting for this feature since PHP 7.0 introduced scalar type declarations and return types, and I, for one, am very excited. We can now set the types of properties in our classes. PHP throws a TypeError if we try to set the type incorrectly.  

<?php declare(strict_types=1);

class TypedProperties
{
    public int $number;
    public string $text;
    public bool $flag;

    public \Monolog\Logger $logger;

    public function run()
    {
        $this->number = '100';
        $this->logger = new \Monolog\Logger('logger');
    }
}

$typedProperties = new TypedProperties();
$typedProperties->run();
Fatal error: Uncaught TypeError: Typed property TypedProperties::$number must be int, string used in typed-properties.php on line 14

https://3v4l.org/Cgdrq

This addition is fantastic. It removes a whole swath of unit tests and type checking code from our codebase, which is always a win. It also detects and removes lots of bugs that we always introduce by using loose typing.

Interestingly, if you set a type to a property PHP will throw an Error if you try to access that property before it’s been set:

Fatal error: Uncaught Error: Typed property TypedProperties::$flag must not be accessed before initialization in typed-properties.php on line 22

Whenever we start adding strict type checking to places in our code we're always improving it. I love it.

GRADE: A+

Arrow Functions

Arrow functions can replace our traditional anonymous functions. They are particularly useful in callbacks where we want to modify the parameter passed in but need some variables in scope from outside that closure.

<?php

$factor = 10;

// pre PHP 7.4
$nums = array_map(function($n) use ($factor) {
        return $n * $factor;
}, [1,2,3,4]);
var_dump($nums);

// PHP 7.4
$nums = array_map(fn($n) => $n * $factor, [1, 2, 3, 4]);

var_dump($nums);

https://3v4l.org/TvZV0

Using the traditional way we need to use the $factor variable to get it in scope so we can use it in our anonymous function. By using the new arrow function, everything is in scope, and we pass the $n parameter by value, so by modifying it, we don't have to return it. Situationally this is very useful but won’t be used too often, it’s particularly good for passing callbacks to PHP's native functions.

GRADE: C

Limited Return Type Covariance and Argument Type Contravariance

So many words. It took some understanding to work out what this feature name means, and that's probably due to my limited computer science background.

In PHP 7.3 or lower, it's impossible to extend a class and overload a method without that method matching the parent's signature exactly, even if the signature change includes a subset of the parent's type. While this sounds complex, it means that fluent interfaces, where the method returns an instance of itself, have been particularly difficult to extend in the past as the context of self changes depending on the class we're using.

<?php

class Producer
{
    public function method(): self
    {
    }
}

class ChildProducer extends Producer
{
    public function method(): self
    {
    }
}

https://3v4l.org/GGdhA

This code generates a fatal error in PHP 7.3:

Fatal error: Declaration of ChildProducer::method(): ChildProducer must be compatible with Producer::method(): Producer in return-type-covariance.php on line 16

This PHP 7.4 feature fixes many headaches, particularly for library authors, indeed, we've already seen some excitement on Twitter from some prominent library authors who are itching to raise support to PHP 7.4.

https://twitter.com/freekmurze/status/1201797483124449286

GRADE: B

Unpacking Inside Arrays

We've had argument unpacking in PHP since PHP 5.6. PHP 7.4 brings splat unpacking to arrays too.

<?php

// PHP 7.3 and older
$parts = ['apple', 'pear'];
$fruits = array_merge(['banana', 'orange'], $parts, ['watermelon']);
var_dump($fruits);

// PHP 7.4
$parts = ['apple', 'pear'];
$fruits = ['banana', 'orange', ...$parts, 'watermelon'];
var_dump($fruits);

https://3v4l.org/XHeQk

For me, this is more of a quality of life improvement than a huge step forward as it can replace multiple array_merge calls cleanly, but remember, I said that about the short array syntax and now I wouldn't use anything else. 

GRADE: D

Numeric Literal Separator

PHP 7.4 now allows us to use underscores in numerical values to help humans read the numbers better.

<?php

$million = 1_000_000;
$billion = 1_000_000_000;
$small = 0.000_000_000_12;

https://3v4l.org/5T1st

This is a nice quality of life change because the computer can always tell what a number is, and anything that makes the programmer's life easier is a huge improvement.

GRADE: B

Allow Exceptions from __toString()

Exceptions that are thrown in __toString() would previously have generated a fatal error.

<?php

class Stringable
{
    protected $handle = 'geeh';
    protected $url = 'twitch.tv/spabby';

    public function __toString()
    {
        if ($this->handle !== 'spabby') {
            throw new Exception('Only spabby can be followed on Twitch');
        }

        return "Give {$this->handle} a follow now at {$this->url}";
    }
}

$stringable = new Stringable();
var_dump((string)$stringable);

https://3v4l.org/3LorB

PHP Fatal error: Method Stringable::__toString() must not throw an exception, caught Exception: Only spabby can be followed on Twitch in to-string-exception.php on line 0

This fatal error is uncatchable without some tiresome workaround hacks that make everyone feel bad. In PHP 7.4, this code works as expected and generates the catchable Exception you'd expect. There's no reason for magic methods to work differently from conventional methods, so bringing this useful magic method into line is a good thing.

GRADE: B

PHP 7.4 is a mixed bag with one crazily useful standout feature.

So there they are, my favourite features of PHP 7.4 graded for your enjoyment. What’s your opinion on my grades? Whether you agree, disagree or are apathetic, let me know in the comments or on Twitter and I’ll get back to you. I can’t wait to see what you build.

  • Email: ghockin@twilio.com
  • Twitter: @GeeH