Skip to main content Headstrong Internet

How to eliminate boilerplate code with PHP 8.1

Published: 2022-11-03 | Updated: 2022-11-03

If you have an application of any appreciable size, you will of course have used DTO (Data Transfer Object) classes to shuttle data around your application.

One of the main properties of a DTO class is that it is immutable. This means that it cannot be changed after it has been created. In PHP we have to jump through a few hoops to create an immutable class, due to lack of native immutability in PHP itself.

Traditionally, creating an immutable class meant creating a class with private properties, and then having only getter methods to access these private properties, and no setter methods at all.

This meant that a typical DTO class consisted of pretty verbose boilerplate code, when all we want it to actually do is carry data without fear of it being modified.

However, now with some of the newer features introduced in PHP 8.0 and later, we can hugely reduce the size of our DTO classes, allowing for a significant reduction in the amount of boilerplate code in our app. Less code for the same functionality is ALWAYS a good thing!

Lets follow a typical DTO class through the various PHP versions to see how it has improved and evolved.

PHP 7.4

In PHP 7.4, a DTO had to be created using a lot of boilerplate code, separately declared private properties, and public methods to access the data in each property.

Here is our example DTO, in its most verbose format.

<?php
declare(strict_types=1);

final class UserNotificationDto
{
    private int $id;

    private string $title;

    private string $shortDescription;

    private string $description;

    private string $icon;

    private bool $acknowledged;

    public function __construct(
        int $id,
        string $title,
        string $shortDescription,
        string $description,
        string $icon,
        bool $acknowledged
    ) {
        $this->id = $id;
        $this->title = $title;
        $this->shortDescription = $shortDescription;
        $this->description = $description;
        $this->icon = $icon;
        $this->acknowledged = $acknowledged;
    }

    public function id(): int
    {
        return $this->id;
    }

    public function title(): string
    {
        return $this->title;
    }

    public function shortDescription(): string
    {
        return $this->shortDescription;
    }

    public function description(): string
    {
        return $this->description;
    }

    public function icon(): string
    {
        return $this->icon;
    }

    public function acknowledged(): bool
    {
        return $this->acknowledged;
    }
}

Lengthy isn’t it? Quite a lot of code to do really very little.

PHP 8.0

With PHP 8.0 we saw the introduction of promoted constructor properties. This allows us to define the class property declarations at the same time as we declare the constructor method parameters.

This allows us to simplify the DTO class a lot. Here’s how it looks in PHP 8.0:

<?php
declare(strict_types=1);

final class UserNotificationDto
{
    public function __construct(
        private int $id,
        private string $title,
        private string $shortDescription,
        private string $description,
        private string $icon,
        private bool $acknowledged
    ) {
    }

    public function id(): int
    {
        return $this->id;
    }

    public function title(): string
    {
        return $this->title;
    }

    public function shortDescription(): string
    {
        return $this->shortDescription;
    }

    public function description(): string
    {
        return $this->description;
    }

    public function icon(): string
    {
        return $this->icon;
    }

    public function acknowledged(): bool
    {
        return $this->acknowledged;
    }
}

It’s much better isn’t it? Less code to read, parse and then maintain - so it’s a definite improvement.

However, we still have all those pesky methods for accessing the private properties.

PHP 8.1

In PHP 8.1 we saw the introduction of the readonly keyword. This allows you to define a property in a class, but the readonly ensures that once it’s been set, it cannot be changed.

We can use this to our advantage by switching our class properties to be public but then also using the readonly keyword to continue providing the immutable behaviour that we are after. And then of course, because the properties are public we no longer have any need for the methods!

<?php
declare(strict_types=1);

final class UserNotificationDto
{
    public function __construct(
        public readonly int $id,
        public readonly string $title,
        public readonly string $shortDescription,
        public readonly string $description,
        public readonly string $icon,
        public readonly bool $acknowledged
    ) {
    }
}

Wow - what an improvement. This is just 15 lines of code compared to the 63 lines for our class in PHP 7.4!

Can we do any better? Well yes, a little, but we need to wait just a short while until PHP 8.2 is released.

PHP 8.2

PHP 8.2 takes the readonly concept one step further, by allowing the readonly keyword to be applied at the class level, so we then don’t need to repeat it on every constructor parameter.

<?php
declare(strict_types=1);

final readonly class UserNotificationDto
{
    public function __construct(
        public int $id,
        public string $title,
        public string $shortDescription,
        public string $description,
        public string $icon,
        public bool $acknowledged
    ) {
    }
}

This is the same lines of code as PHP 8.1 but less noise - it just looks a lot neater.

Conclusion

Removing boilerplate code from your application is an easy way to reduce the amount of code you have to maintain. Particularly with classes such as DTO’s where there really isn’t any value provided by the boilerplate methods - they are just immutable data classes - it’s a huge improvement to be able to eliminate all this noise.

Features like this are one of the best reasons to upgrade to more modern versions of PHP, quite apart from the obvious performance and security benefits that newer versions bring.

I’ve been able to strip out thousands of lines of boilerplate code from some of my applications, without changing their behaviour in the slightest. Less code means fewer bugs, better performance and lower memory usage to boot!

Back to top

Application Development

Unlock the value in your business with custom software solutions.

Save time and money, and keep all your customers happy.

Cloud Server Management

We can manage your infrastructure, ensuring your application is always available and performant.

Flexible solutions for all types of app.

Software Consulting

Got a new software project? Don't know where to start?

We can help you plan, design and build a successful application for your business.

Website Design & Build

Development of all types of website from personal blogs to e-commerce sites.

We work with WordPress, CraftCMS, Symfony and more.

Headstrong Logo