PHP 8: Constructor Property Promotion

Introduction

If you have been a software engineer for a while, you know that software engineers love using scary names to describe simple things. The term constructor property promotion should not scare you because you might be using it in your codebase already without realizing it has a fancy name.

Here are the things you will achieve after reading this article.

  1. You will be able to refactor a PHP class to use constructor property promotion instead of using the default syntax used when setting class properties in the constructor function.
  2. You will know the different ways of accessing class properties after setting them using the constructor property promotion syntax.
  3. You will know the common mistakes that lead to errors when using the constructor property promotion syntax in your PHP class and how to avoid them.

Interested? Let's move 🚀

Prerequisites

  1. A basic understanding of Object-Oriented Programming in PHP
  2. You must have PHP 8 installed to enjoy this feature in your code or project. Alternatively, you can test this feature on phpsandbox by selecting PHP8 as your preferred version

What is Constructor Property Promotion? 🤔

Constructor property promotion is a feature introduced in PHP 8 that allows values passed to a constructor to be automatically set as class properties without the need to write the assignment statement in the body of the constructor.
For a better understanding of the concept, let's take a look at the way values were assigned to class properties before the introduction of the constructor property promotion feature in PHP8.

Before constructor property promotion 🥱

Before constructor property promotion was introduced, here’s how you will typically set the
firstName and lastName properties passed to the Employee class through the constructor.

<?php

class Employee
{

  protected $firstName, $lastName;

  public function __construct(string $firstName, string $lastName)
  {
    $this->firstName = $firstName;
    $this->lastName = $lastName;
  }
}


$employee = new Employee('Ibrahim', 'Alausa');

In the code above, we are declaring the properties firstName and lastName without any initial value. Then, in the body of the constructor, we set the firstName and lastName properties to the value passed to the constructor. In this example, that is **Ibrahim **as the value of the firstName property and **Alausa **as the value of the lastName property.

The new way for the cool programmers 😎

Now, let's rewrite the Employee class to use constructor property promotion. Let's see what our code will look like in this case

<?php

class Employee
{
  public function __construct(protected string $firstName, protected string $lastName)
  {
  }
}


$employee = new Employee('Ibrahim', 'Alausa');

That's it. Yes. Isn't this beautiful? Just in case your answer is *NO * well, that was a rhetorical question, my friend. It is beautiful.

What exactly is different

By adding an access modifier (protected, private, etc) to each parameter in the constructor, PHP understands that you are trying to “promote” the constructor parameter to a class property.

Important points to note when working with constructor property promotion

1. Accessing class properties 🔐

Within the constructor, promoted properties can be accessed with or without the $this keyword since they are still within the function scope where they were declared. Let's see what our code will look like in this case

<?php

class Employee
{
  public function __construct(protected string $firstName, protected string $lastName)
  {
    var_dump($firstName);  Ibrahim ✔️
    var_dump($this->firstName); Ibrahim ✔️
  }
}


$employee = new Employee('Ibrahim', 'Alausa');

Run the code here to see for yourself.

However, once you are outside the constructor, you need to use the $this keyword to access all promoted properties so that PHP understands that you are referring to the firstName or lastName property of the class and not an undefined variable or a variable that may have been declared using the same name.

<?php

class Employee
{
  public function __construct(protected string $firstName, protected string $lastName)
  {
  }

  public function getUndefinedFirstName()
  {
    var_dump($firstName); // Output: Undefined variable '$firstName' ❌
  }

  public function getWrongFirstName()
  {
    $firstName = 'John';
    var_dump($firstName); // Output:John ❌
  }

  public function getFirstName()
  {
    var_dump($this->firstName); // Output:Ibrahim ✔️
  }
}


$employee = new Employee('Ibrahim', 'Alausa');

Run the code here to see for yourself.

2. You don't have to promote all constructor parameters. Mix 'em up 🥂

Let’s assume that for some reason, we need to append Fname_ to every value passed to our Employee class as the first name and we want to do that cleanly. We don’t need to promote the firstName property. Let's see what our code will look like in this case.

<?php

class Employee
{
  protected $firstName;

  public function __construct(string $firstName, protected string $lastName)
  {
    $this->firstName = "Fname_$firstName";
  }

  public function getFirstName()
  {
    var_dump($this->firstName); // Output:Fname_Ibrahim ✔️
  }
}


$employee = new Employee('Ibrahim', 'Alausa');

Run the code here to see for yourself.

3. You either want to promote a property or you don't. Make a choice 🤦‍♂️

This means that you can't declare a class property above the constructor and still try to promote that property in the constructor parameter list. Let's see what our code will look like in this case. Remember, this will throw an error.

<?php

class Employee
{
  protected $firstName;

  public function __construct(protected string $firstName, protected string $lastName) 
  //Cannot redeclare Employee::$firstName ❌
  {
    $this->firstName = $firstName;
  }
}


$employee = new Employee('Ibrahim', 'Alausa');

Run the code here to see for yourself.

4. You can set default values for promoted properties 😐

If one or more values in the constructor are optional, a default value can be set for that property.
Let's see what our code will look like in this case.

<?php

class Employee
{
  public function __construct(protected string $firstName, protected string $lastName='N/A') 
  {
  }

  public function getLastName()
  {
    var_dump($this->lastName); //Output: N/A ✔️
  }
}

$employee = new Employee('Ibrahim');

Run the code here to see for yourself.

Quick Recap

  1. The constructor property promotion feature only works with PHP8.0 and above.
  2. To promote a constructor parameter to a class property, the constructor parameter should have an access modifier like public, private, etc.
  3. Since the constructor parameters are both parameters and class properties, you can access the promoted properties in the constructor with or without the $this keyword. However, class properties must be accessed with the this keyword outside the constructor function.
  4. Not all parameters need to be promoted. Mix 'em up and enjoy the best of both worlds.
  5. While trying to enjoy the best of both worlds, remember that you can't declare a class property above the constructor and still try to promote that property in the constructor parameter list.
  6. Default values can be set for promoted properties in the constructor.

It's a wrap 🎉

PHP8 comes with a lot of amazing features that will make you write shorter and cleaner code. If you can, upgrade your version and start using it today.

Thanks for sticking with me till the end. If you have any suggestions or feedback, kindly drop them in the comment section. Enjoy the rest of your day...bye 😊.

15