Since PHP 8.1, class properties can be declared as readonly. This means that class property can be initialized once and cannot be modified later. Readonly properties are declared with readonly
keyword.
Let's say we have User
class which has readonly property.
<?php
class User
{
private readonly int $id;
public function setId(int $id): void
{
$this->id = $id;
}
}
Next, we created an instance of the User
class. A second call of the setId
method produces a fatal error because id
property already set by the first setId
method call.
<?php
require_once 'User.php';
$user = new User();
$user->setId(10); // OK
$user->setId(20); // Error
Fatal error: Uncaught Error: Cannot modify readonly property User::$id in ...
There are some notes for readonly properties.
Only allowed on typed properties
Readonly properties should be declared with type. The reason is that properties declared without a type has null value by default and is not compatible with readonly properties.
<?php
class User
{
private readonly int $id; // OK
private readonly $name; // Error
}
Fatal error: Readonly property User::$name must have type in User.php on line 7
Only initialized inside the class
Readonly properties can only be initialized inside the class, either from the constructor or method. Readonly properties cannot be initialized outside the class (from global scope).
<?php
class User
{
private readonly int $id;
private readonly string $name;
public readonly int $age;
public function __construct(int $id)
{
$this->id = $id;
}
public function setName(string $name): void
{
$this->name = $name;
}
}
<?php
require_once 'User.php';
$user = new User(10); // OK
$user->setName('John'); // OK
$user->age = 25; // Error
Fatal error: Uncaught Error: Cannot initialize readonly property User::$age from global scope in main.php:7
Allowed with promoted properties
Readonly properties can be declared in constructor as promoted properties as well.
<?php
class User
{
public function __construct(private readonly int $id) // OK
{
}
}
Default value is not allowed
Readonly properties cannot have default value.
<?php
class User
{
private readonly string $role = 'Viewer'; // Error
}
Fatal error: Readonly property User::$role cannot have default value in User.php on line 5
Unset is not allowed
Readonly properties cannot be unset after initialization.
<?php
class User
{
private readonly int $id;
public function __construct(int $id)
{
$this->id = $id;
}
public function unsetId(): void
{
unset($this->id); // Error
}
}
<?php
require_once 'User.php';
$user = new User(10);
$user->unsetId();
Fatal error: Uncaught Error: Cannot unset readonly property User::$id in User.php:14
Redeclaration is not allowed in inheritance
When a child class extends the parent class, it is not allowed to override a readonly property with a read-write property.
<?php
class User
{
public readonly string $id;
}
<?php
class Student extends User
{
public string $id; // Error
}
Fatal error: Cannot redeclare readonly property User::$id as non-readonly Student::$id in ...
This rule applies in the opposite way as well. It is not allowed to override a read-write property with a readonly property.
<?php
class User
{
public string $id;
}
<?php
class Student extends User
{
public readonly string $id; // Error
}
Fatal error: Cannot redeclare non-readonly property User::$id as readonly Student::$id in ...
Leave a Comment
Cancel reply