Properties are class member variables that store values like strings, integers, boolean, etc. We can set properties via class constructor, setter method or directly if property is public.
When we set properties via constructor, the class can be written as follows:
<?php
class User
{
private string $username;
private int $roleId;
private bool $active;
public function __construct(string $username, int $roleId, bool $active)
{
$this->username = $username;
$this->roleId = $roleId;
$this->active = $active;
}
}
As we can see, properties names were repeated four times: in class property declaration, in constructor parameters, and two times when assigning property value in the body of the constructor.
Since PHP 8.0, we can use constructor property promotion. This is a new syntax that allows to combine properties declaration, constructor parameters and properties assignments in one place.
We can rewrite the previous code as follows:
<?php
class User
{
public function __construct(
private string $username,
private int $roleId,
private bool $active
) {
}
}
As we can see, properties were declared and assigned via class constructor. We need to write properties names just once instead of four times.
There are some notes for constructor property promotion.
The visibility of a property
Property is promoted when it declared in the constructor with visibility. We can use public
, protected
or private
visibility keywords. The visibility of properties don't need to be the same, it can be mixed.
<?php
class User
{
public function __construct(
public string $username,
protected int $roleId,
private bool $active,
string $email
) {}
}
Note: $email
is just constructor parameter and not promoted property because visibility is not specified.
Standard constructor parameters
Promoted properties can be declared together with standard constructor parameters. The order doesn't matter.
<?php
class User
{
private string $email;
public function __construct(
private string $username, // Promoted property
string $email // Standard constructor parameter
) {
$this->email = $email;
}
}
No duplicates
Property cannot be declared in the constructor as promoted property if property already declared in the class.
<?php
class User
{
private string $username;
public function __construct(private string $username) {}
}
Fatal error: Cannot redeclare User::$username in User.php on line 7
Reassign promoted property
Promoted properties can be reassigned in the body of the constructor or do other logic.
<?php
class User
{
public function __construct(private string $username)
{
echo $this->username; // john
$this->username = 'james';
echo $this->username; // james
}
}
<?php
require_once 'User.php';
$user = new User('john');
Default value
Promoted property can be declared with default value.
<?php
class User
{
public function __construct(
public string $username,
public int $roleId = 1
) {}
}
<?php
require_once 'User.php';
$user = new User('john');
echo $user->username; // john
echo $user->roleId; // 1
The var keyword
To declare property using legacy syntax with var
keyword is not allowed for property promotion.
<?php
class User
{
public function __construct(var string $username) {}
}
Parse error: syntax error, unexpected token "var", expecting variable in User.php on line 5
The type of a property
To be property promoted, the type of property is not required.
<?php
class User
{
public function __construct(
private string $username, // Promoted property
private $email // Promoted property too
) {}
}
The callable type
The callable
type is not allowed as a property type. So, it is not allowed for property promotion too.
<?php
class User
{
public function __construct(private callable $callback) {}
}
Fatal error: Property User::$callback cannot have type callable in User.php on line 5
Variadic parameters
Variadic parameters cannot be used for property promotion.
<?php
class User
{
public function __construct(private string ...$params) {}
}
Fatal error: Cannot declare variadic promoted property in User.php on line 5
Nullable types
Nullable types must be explicitly declared by specifying ?
before type definition.
<?php
class User
{
public function __construct(
private ?string $username,
private ?int $roleId = null
) {}
}
Implicit nullable types (without ?
, but has null
as default value) are not supported for property promotion.
<?php
class User
{
public function __construct(
private string $username = null,
private int $roleId = null
) {}
}
Fatal error: Cannot use null as default value for parameter $username of type string in User.php on line 5
Only constructor
Promoted properties can be declared only in the constructor. In other methods cannot.
<?php
class User
{
public function setUsername(private string $username) {}
}
Fatal error: Cannot declare promoted property outside a constructor in User.php on line 5
Abstract constructor
Promoted properties cannot be declared in an abstract constructor.
<?php
abstract class AbstractUser
{
abstract public function __construct(private string $username);
}
Fatal error: Cannot declare promoted property in an abstract constructor in AbstractUser.php on line 5
Interface constructor is considered as abstract. So promoted properties cannot be declared in the interface constructor.
<?php
interface UserInterface
{
public function __construct(private string $username);
}
Fatal error: Cannot declare promoted property in an abstract constructor in UserInterface.php on line 5
Trait constructor
It is allowed to declare promoted properties in the trait constructor.
<?php
trait UserTrait
{
public function __construct(private string $username) {}
}
Doc comments
Doc comments can be added on promoted properties and can be retrieved using the Reflection API.
<?php
class User
{
public function __construct(
/** @var string */
private $username
) {}
}
<?php
require_once 'User.php';
$property = new ReflectionProperty(User::class, 'username');
echo $property->getDocComment(); // /** @var string */
Attributes
Attributes are allowed on promoted properties.
<?php
class User
{
public function __construct(
#[Column('string')]
private string $username
) {}
}
<?php
require_once 'User.php';
$property = new ReflectionProperty(User::class, 'username');
foreach ($property->getAttributes() as $attribute) {
echo $attribute->getName(); // Column
foreach ($attribute->getArguments() as $arg) {
echo $arg; // string
}
}
Leave a Comment
Cancel reply