Skip to content
  • Homepage
  • HTML
  • CSS
  • Symfony
  • PHP
  • How to
  • Contact
  • Donate

Teach Developer

Articles, Guides & Tips

PHP 8: Constructor property promotion

Home  »  PHP   »   PHP 8: Constructor property promotion
Posted on September 19, 2022September 19, 2022
704

I’m very happy with the constructor property promotion RFC, it’s passed and will be added in PHP 8. You see, this feature reduces a lot of boilerplate code when constructing simple objects such as VOs and DTOs.

In short: property promotion allows you to combine class fields, constructor definition, and variable assignments all into one syntax, in the construct parameter list.

So instead of doing this:

class CustomerDTO
{
    public string $name;

    public string $email;

    public DateTimeImmutable $birth_date;

    public function __construct(
        string $name, 
        string $email, 
        DateTimeImmutable $birth_date
    ) {
        $this->name = $name;
        $this->email = $email;
        $this->birth_date = $birth_date;
    }
}

You would write this:

class CustomerDTO
{
    public function __construct(
        public string $name, 
        public string $email, 
        public DateTimeImmutable $birth_date,
    ) {}
}

Let’s look at how it works!

How it works

The basic idea is simple: ditch all the class properties and the variable assignments, and prefix the constructor parameters with public, protected or private. PHP will take that new syntax, and transform it to normal syntax under the hood, before actually executing the code.

So it goes from this:

class MyDTO
{
    public function __construct(
        public string $name = 'Teach',
    ) {}
}

To this:

class MyDTO
{
    public string $name;

    public function __construct(
        string $name = 'Teach'
    ) {
        $this->name = $name;
    }
}

And only executes it afterward.

Note by the way that the default value is not set on the class property, but on the method argument in the constructor.

Promoted property properties

So let’s look at what promoted properties can and can’t do, there are quite a lot of little intricacies worth mentioning!

Only in constructors

Promoted properties can only be used in constructors. That might seem obvious but I thought it was worth mentioning this, just to be clear.

No duplicates allowed

You’re not able to declare a class property and a promoted property with the same name. That’s also rather logical, since the promoted property is simply transpired to a class property at runtime.

class MyClass
{
    public string $a;

    public function __construct(
        public string $a,
    ) {}
}

Untyped properties are allowed

You’re allowed to promote untyped properties.

class MyDTO
{
    public function __construct(
        public $untyped,
    ) {}
}

Simple defaults

Promoted properties can have default values, but expressions like new … these are not allowed.

public function __construct(
    public string $name = 'Teach',
    public DateTimeImmutable $date = new DateTimeImmutable(),
) {}

Combining promoted- and normal properties

Not all constructor properties should be promoted, you can mix and match.

class MyClass
{
    public string $b;

    public function __construct(
        public string $a,
        string $b,
    ) {
        $this->b = $b;
    }
}

I’d say: be careful mixing the syntaxes, if it makes the code less clear, consider using a normal constructor instead.

Access promoted properties from the constructor body

You’re allowed to read the promoted properties in the constructor body. This can be useful if you want to do extra validation checks. You can use both the local variable and the instance variable, both work fine.

public function __construct(
    public int $a,
    public int $b,
) {
    assert($this->a >= 100);

    if ($b >= 0) {
        throw new InvalidArgumentException('…');
    }
}

Doc comments on promoted properties

You can add doc comments on promoted properties, and they are still available via reflection.

class MyClass 
{
    public function __construct(
        /** @var string */
        public $a,
    ) {}
}
$property = new ReflectionProperty(MyClass::class, 'a');

$property->getDocComment(); // "/** @var string */"

Attributes

Just like doc blocks, attributes are allowed on promoted properties. When transpired, they will be present both on the constructor parameter, as well as the class property.

class MyClass
{
    public function __construct(
        #[MyAttribute]
        public $a,  
    ) {}
}

Will be transpiled to:

class MyClass 
{
    #[MyAttribute]
    public $a;
 
    public function __construct(
        #[MyAttribute]
        $a,
    ) {
        $this->a = $a;
    }
}

Not allowed in abstract constructors

I didn’t even know abstract constructors were a thing, but here goes! Promoted properties are not allowed in them.

abstract class A
{
    abstract public function __construct(
        public string $a,
    ) {}
}

Allowed in traits

On the other hand, they are allowed in traits. This makes sense since the transpiled syntax is also valid in traits.

trait MyTrait
{
    public function __construct(
        public string $a,
    ) {}
}

var is not supported

Old, I mean, experienced PHP developers might have used var in a distant past to declare class variables. It’s not allowed with constructor promotion. Only public, protected and private are valid keywords.

public function __construct(
    var string $a,
) {}

Variadic parameters cannot be promoted

Since you can’t convert to a type that’s, it’s not possible to promote variadic parameters.

public function __construct(
    public string ...$a,
) {}

Still waiting for generics…

Reflection for isPromoted

Both ReflectionProperty and ReflectionParameter have a new isPromoted method to check whether the class property or method parameter is promoted.

Inheritance

Since PHP constructors don’t need to follow the declaration of their parent constructor, there’s little to be said: inheritance is allowed. If you need to pass properties from the child constructor to the parent constructor though, you’ll need to manually pass them:

class A
{
    public function __construct(
        public $a,
    ) {}
}

class B extends A
{
    public function __construct(
        $a,
        public $b,    
    ) {
        parent::__construct($a);
    }
}
PHP

Post navigation

Previous Post: How to Send Email from Localhost in PHP
Next Post: What’s new in PHP 8.2

Related Posts

  • How to PHP Get Max Value From Array
  • How to Send Email from Localhost in PHP
  • How to Convert PHP CSV to JSON
  • How to check the PHP version
  • How to split a string into an array with Twig
  • How to remove index.php from URL in CodeIgniter 4

Categories

  • Codeigniter (3)
  • CSS (11)
  • eCommerce (1)
  • Framework (1)
  • Git (3)
  • How to (43)
  • HTML (5)
  • JavaScript (15)
  • Jquery (7)
  • Laravel (1)
  • Linux (4)
  • Magento-2 (1)
  • Node js (4)
  • Others (2)
  • PHP (11)
  • React (13)
  • Server (1)
  • SSH (3)
  • Symfony (6)
  • Tips (16)
  • Top Tutorials (10)
  • Ubuntu (3)
  • Vue (1)
  • Wordpress (7)

Latest Posts

  • What is SSH in Linux?
  • How to Delete Files in Ubuntu Command Line
  • How to Deploy a React application on a cPanel
  • How to use events listeners and Event Subscriber in Symfony
  • How to Convert PHP CSV to JSON

WEEKLY TAGS

AJAX (1) Codeigniter (1) Javascript (11) JQuery (1) PHP (16) Programming (1) React (3) Symfony (1)

Random Post

How to Delete Files in Ubuntu Command Line
How to make the div move up and down when scrolling the page with CSS?
What's new in PHP 8.2
How to Check Twig Version in Symfony
How to Make Toggles With React Hooks

Quick Navigation

  • About
  • Contact
  • Privacy Policy

© Teach Developer 2021. All rights reserved