Backend Development

Constructor Property Promotion In PHP 8.0

Constructor Property Promotion In PHP 8

Constructor Property Promotion is a feature in PHP 8.0 related to constructor arguments. Let’s see this feature in this article. 

 

 

To describe the Class Constructor Property Promotion in PHP look at this example:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
class Product
{
public int $id;
public string $name;
public float $price;
function __construct(int $id, string $name, float $price)
{
$this->id = $id;
$this->name = $name;
$this->price = $price;
}
}
<?php class Product { public int $id; public string $name; public float $price; function __construct(int $id, string $name, float $price) { $this->id = $id; $this->name = $name; $this->price = $price; } }
<?php

class Product
{
    public int $id;
    public string $name;
    public float $price;

    function __construct(int $id, string $name, float $price)
    {
         $this->id = $id;
         $this->name = $name;
         $this->price = $price;
    }
}

In this class we have three properties for the product, ($id, $name, $price). The constructor also accepts these argument so whenever creating any instance of this class you have to provide these arguments. This is a common example we usually see a lot. 

By using the Constructor Property Promotion we can rewrite this example in a simple way:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<?php
class Product
{
function __construct(public int $id, public string $name, public float $price)
{
}
}
<?php class Product { function __construct(public int $id, public string $name, public float $price) { } }
<?php

class Product
{
    function __construct(public int $id, public string $name, public float $price)
    {
    }
}

As shown in the code the Property Promotion feature allow us to do class property declaration and property assignment right from the constructor. So this code is pretty similar to the original code. This enables us shorten big classes that contain many properties. 

 

How this works?

Typically when a constructor argument includes a modifier such as public, private, protected, etc, PHP interpreter will interpret it as an object property and a constructor argument, then assign the argument value to the property. 

Note that this feature from PHP 8.0 and later so you can’t use it in PHP < PHP 8.0

 

Promoted Property & Modifiers

So to make a class property to be Promoted you have to provide a visibility modifier (public, private, protected) in front of it like so:

Example 1:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class User {
function __construct(public string $username) {}
}
class User { function __construct(public string $username) {} }
class User {
      function __construct(public string $username) {}
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
$user = new User('John');
echo $user->username;
$user = new User('John'); echo $user->username;
$user = new User('John');
echo $user->username;

Example 2:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Product
{
function __construct(private int $id, public string $name, protected float $price)
{
}
function getId()
{
return $this->id;
}
function getPrice()
{
return $this->price;
}
}
$product = new Product(2, "New Product", 100);
echo "Product ($product->name) #{$product->getId()} cost {$product->getPrice()}";
class Product { function __construct(private int $id, public string $name, protected float $price) { } function getId() { return $this->id; } function getPrice() { return $this->price; } } $product = new Product(2, "New Product", 100); echo "Product ($product->name) #{$product->getId()} cost {$product->getPrice()}";
class Product
{
    function __construct(private int $id, public string $name, protected float $price)
    {
    }

    function getId()
    {
    	return $this->id;
    }

    function getPrice()
    {
    	return $this->price;
    }
}

$product = new Product(2, "New Product", 100);
echo "Product ($product->name) #{$product->getId()} cost {$product->getPrice()}";

You can use also use the readonly modifier in PHP 8.1 to make the property promoted as shown:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Product
{
function __construct(private int $id, public string $name, readonly int $price)
{
}
}
class Product { function __construct(private int $id, public string $name, readonly int $price) { } }
class Product
{
    function __construct(private int $id, public string $name, readonly int $price)
    {
    }
}

 

Omitting the visibility modifier make the property unpromoted, therefore you have to initialize it the old way:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class User
{
public string $username;
function __construct(string $username)
{
$this->username = $username;
}
}
class User { public string $username; function __construct(string $username) { $this->username = $username; } }
class User 
{ 
    public string $username;

    function __construct(string $username) 
    {
        $this->username = $username;
    } 
}

 

 

Mixing Promoted and Non Promoted Properties

You can mix the Constructor Promoted and Non-Promoted properties in a single constructor:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Product
{
public float $price;
function __construct(public int $id, public string $name, float $price)
{
$this->price = $price;
}
}
$product = new Product(2, "New Product", 100);
echo $product->name . " with price (" . $product->price . ")";
class Product { public float $price; function __construct(public int $id, public string $name, float $price) { $this->price = $price; } } $product = new Product(2, "New Product", 100); echo $product->name . " with price (" . $product->price . ")";
class Product
{
    public float $price;

    function __construct(public int $id, public string $name, float $price)
    {
    	$this->price = $price;
    }
}

$product = new Product(2, "New Product", 100);
echo $product->name . " with price (" . $product->price . ")";

As you see the $price property is a non-promoted property.

 

Not Allowed Duplicated Properties

You can’t declare a standard property and promoted property with the same name as this results in a fatal error:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Product
{
public float $price;
function __construct(public int $id, public string $name, public float $price)
{
}
}
class Product { public float $price; function __construct(public int $id, public string $name, public float $price) { } }
class Product
{
    public float $price;

    function __construct(public int $id, public string $name, public float $price)
    {

    }
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Fatal error: Cannot redeclare Product::$price in ....
Fatal error: Cannot redeclare Product::$price in ....
Fatal error: Cannot redeclare Product::$price in ....

 

You can remove type hints from properties

Type hints or typed properties isn’t required when using promoted properties although it’s better to type hint properties but it’s not a requirement as in this example: 

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class User
{
function __construct(public $username)
{
}
}
$user = new User("Wael Salah");
echo $user->username;
class User { function __construct(public $username) { } } $user = new User("Wael Salah"); echo $user->username;
class User 
{ 
    function __construct(public $username) 
    {
    } 
}
$user = new User("Wael Salah");
echo $user->username;

 

Allowed in Traits

As PHP traits can contain constructors, methods and properties, so you can use Constructor Property Constructor as well:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
trait ResponseTrait
{
function __construct(public string $message, public int $statusCode)
{}
}
trait ResponseTrait { function __construct(public string $message, public int $statusCode) {} }
trait ResponseTrait
{
    function __construct(public string $message, public int $statusCode)
    {}
}

 

Promoted Properties in Interfaces & Abstract Classes

Interfaces not support promoted properties, any attempt to use them it will trigger a fatal error:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
interface PostType
{
public function __construct(public array $params);
}
interface PostType { public function __construct(public array $params); }
interface PostType
{
    public function __construct(public array $params);
}
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
Fatal error: Cannot declare promoted property in an abstract constructor in ...
Fatal error: Cannot declare promoted property in an abstract constructor in ...
Fatal error: Cannot declare promoted property in an abstract constructor in ... 

In abstract classes promoted properties supported only if the constructor not marked as abstract:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
abstract class PostType
{
public function __construct(public array $params) {} // Valid
}
abstract class PostType { public function __construct(public array $params) {} // Valid }
abstract class PostType
{
    public function __construct(public array $params) {}   // Valid
}

If the abstract class constructor marked as abstract then promoted properties not allowed:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
abstract class PostType
{
abstract public function __construct(public array $params); // Not Valid
}
Fatal error: Cannot declare promoted property in an abstract constructor
abstract class PostType { abstract public function __construct(public array $params); // Not Valid } Fatal error: Cannot declare promoted property in an abstract constructor
abstract class PostType
{
    abstract public function __construct(public array $params);   // Not Valid
}

Fatal error: Cannot declare promoted property in an abstract constructor

 

 

0 0 votes
Article Rating

What's your reaction?

Excited
0
Happy
0
Not Sure
0
Confused
1

You may also like

Subscribe
Notify of
guest


0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments