slices

PHP 8 - Constructor Property Promotion

Note This is a PHP 8 feature – code discussed here will fail in older versions of PHP.

This lovely feature cuts down boilerplate in class definitions by at least half, making your code more readable and, because it reduces repetition, less prone to errors.

In essence constructor property promotion lets you declare class properties, assign default and user provided values all in the constructor signature.

How? Read on.

The problem

Here’s a sample class. It is designed to store a set of four co-ordinates

namespace giblog;

class Square
{
    private $x1=0;
    private $y1=0;
    private $x2=0;
    private $y2=0;

    public function __construct($x1=0, $y1=0, $x2=0, $y2=0)
    {   
        int $this->x1 = $x1;
        int $this->y1 = $y1;
        int $this->x2 = $x2;
        int $this->y2 = $y2;
    }   

    public function coords()
    {   
        return [$this->x1, $this->y1, $this->x2, $this->y2];
    }   
}

So this is pretty straightforward. The Square class simply manages four integer properties. But what a lot of work to declare and store them. First of all I must explicitly declare each one – from $x1 to $y2. Then I must declare the constructor argument list. And then I must assign the provided arguments to the properties within the body of the constructor. I’m drowning in $x and $y arguments and properties!

That’s a lot of opportunities for a typo. I nearly didn’t bother with a test for such a trivial class. But I’m glad I did. With all those eye confounding little property and variable names I found two errors!

First off, here was my test.

class SquareTest extends TestCase
{
    public function testSquare()
    {   
        $square = new Square(1,2,3,4);
        self::assertEquals([1,2,3,4], $square->coords());
    }   
}

Here’s typo number one:

    public function __construct($x1=0, $x1=0, $x2=0, $y2=0)

That second $x1 should have been $y1.

And typo number two:

        $this->x1 = $x1;
        $this->y1 = $y1;
        $this->x2 = $x2;
        $this->x2 = $y2;

That last line: $this->x2 = $y2; should have been $this->y2 = $y2;.

This kind of error is insidious because it won’t cause a warning. It’s only if your testing is up to snuff that you will catch it early.

Constructor Property Promotion to the rescue

If only we could get rid of all that duplication. Well, of course, I’m going to tell you that we can. Here is constructor property promotion in action:

namespace giblog;

class Square2
{
    public function __construct(
        private int $x1=0, 
        private int $y1=0,
        private int $x2=0,
        private int $y2=0)
    {   
    }   

    public function coords()
    {   
        return [$this->x1, $this->y1, $this->x2, $this->y2];
    }   
}

Notice how I placed the access control keyword in the constructor’s argument list. That tells PHP that we wish to declare and assign a property right there. No need to declare the property in the class and no need for any explicit assignment.

I have reduced the likelyhood of typo bugs. Also, once you’re used to the syntax, the class is much easier to read at a glance. Since there’s less boilerplace code to work through – you can cut straight to the logic of the code.

How do I run the code?

It depends when you’re reading this. At the time of writing, you’ll need to compile a development version of PHP. The best starting point to build your own bleeding edge PHP instance is the PHP site’s git instructions – followed by the README.md file (nicely formatted on Github). Want a blog post on build? Ping me @getinstance_mz.

If you’re reading this after December 2020 then, first of all, you’ll know who won the US election. That blows my mind. Secondly, PHP 8 should have been released, so you may find it whereever you usually get your PHP. Otherwise, the official PHP site install page will be a good place to visit

Photo by Jessica Lewis on Unsplash