PHP Readonly Properties and Classes Explained
Modern PHP has introduced powerful features to support immutability and prevent unintended data modification. This article explores readonly properties, introduced in PHP 8.1, and readonly classes, introduced in PHP 8.2. You will learn how these features work, their syntax, key rules, and how they simplify the creation of secure and robust Data Transfer Objects (DTOs) and Value Objects.
Readonly Properties (PHP 8.1)
Readonly properties allow you to declare class properties that can only be initialized once. Once a value is assigned to a readonly property, it cannot be modified or unset from any scope. This ensures that the data inside your object remains consistent throughout its lifecycle.
Key Rules for Readonly Properties
- Must be typed: Readonly properties must have an
explicit type (e.g.,
string,int,array, or a class name). If you need a flexible type, you can usemixed. - No default values: You cannot assign a default value directly to a readonly property in its declaration, as that counts as initialization.
- Initialization scope: They can only be initialized from within the class where they are defined (typically in the constructor).
Code Example
class User {
public readonly string $username;
public readonly int $id;
public function __construct(int $id, string $username) {
$this->id = $id;
$this->username = $username;
}
}
$user = new User(1, 'alice');
// $user->username = 'bob'; // Throws a Error: Cannot modify readonly propertyReadonly Classes (PHP 8.2)
PHP 8.2 built upon this concept by introducing readonly classes.
Instead of marking every single property in a class as
readonly, you can mark the class itself. When a class is
declared as readonly, all of its non-static properties
automatically inherit the readonly behavior.
Key Rules for Readonly Classes
- Implicit readonly properties: Every property in a readonly class is automatically treated as readonly.
- All properties must be typed: Since all properties in the class are readonly, they must all have explicit types.
- No dynamic properties: Readonly classes prevent the creation of dynamic (undeclared) properties, which helps avoid bugs and typos.
- Inheritance restriction: A class that extends a readonly class must also be declared as readonly.
Code Example
readonly class DatabaseConfig {
public function __construct(
public string $host,
public int $port,
public string $username
) {}
}
$config = new DatabaseConfig('127.0.0.1', 3306, 'root');
// $config->port = 5432; // Throws an Error: Cannot modify readonly propertySummary of Use Cases
Use readonly properties when you want a hybrid object where some properties can change over time (such as an updated timestamp or status), but core identifiers (like an ID) must remain constant.
Use readonly classes when you are building strictly immutable objects, such as Data Transfer Objects (DTOs), configuration objects, or Domain Value Objects, where the entire state of the object must remain untouched after creation.