With PHP 8.1, a powerful new feature was introduced to the object-oriented programming (OOP) paradigm: readonly properties. This addition allows developers to define properties that can only be assigned once and are immutable after initialization. By enabling greater control over data integrity, readonly properties help you write more predictable, secure, and bug-free code.
In this article, we'll dive into what readonly properties are, how they work, and how they can be utilized effectively in modern PHP applications. We'll also cover practical examples and use cases with the latest PHP syntax.
What Are Readonly Properties?
A readonly property is a property in a PHP class that can only be assigned once, usually during object construction. Once assigned, the value of this property cannot be modified. This means that the property is essentially immutable after being set.
In a nutshell, readonly properties enforce immutability for class attributes, which helps ensure that objects maintain a consistent state throughout their lifecycle.
Key Features of Readonly Properties:
- A readonly property can be initialized only once, either at declaration or within the constructor.
- After it has been initialized, any attempts to modify it will result in a runtime error.
- Readonly properties can only be declared with non-static properties.
- They promote safer code and better data encapsulation, especially in object models with constant values or data that shouldn’t change after initialization.
Defining Readonly Properties in PHP
Let's look at the syntax to define a readonly property in a class. Here's how you can declare a readonly property in PHP 8.1+
<?php
class User {
public readonly string $username;
public readonly int $id;
public function __construct(string $username, int $id) {
$this->username = $username;
$this->id = $id;
}
}
$user = new User('john_doe', 101);
echo $user->username; // Outputs: john_doe
echo $user->id; // Outputs: 101
// Attempting to modify a readonly property will cause an error
// $user->username = 'jane_doe'; // Error: Cannot modify readonly property User::$username
Breaking Down the Syntax:
-
public readonly string $username;
: This is how you declare a readonly property. You use thereadonly
keyword, followed by the visibility modifier (public
,protected
, orprivate
), the data type, and the property name. -
Inside the constructor, we can assign values to the readonly properties. Once set, these values cannot be changed during the object’s lifecycle.
-
If you try to reassign a value to a readonly property, a runtime error will occur:
Error: Cannot modify readonly property
.
Benefits of Readonly Properties
Readonly properties introduce several advantages to PHP developers:
-
Immutable Data Structures: Readonly properties enforce immutability, ensuring that critical data within an object remains unchanged after initialization. This is particularly useful for objects that represent fixed data such as configuration settings, user identities, or constant values.
-
Improved Data Integrity: By preventing unintended changes to object properties, readonly properties reduce bugs caused by accidental or malicious property modifications.
-
Cleaner, Simpler Code: Instead of manually managing property immutability through getter-only methods, readonly properties simplify the process by allowing you to declare immutability directly in the class definition.
-
Performance Boosts: Immutable objects are easier to optimize and manage in memory because the state doesn't change. In certain cases, this can lead to performance improvements.
Readonly Properties with Default Values
You can also assign a default value to a readonly property directly at the time of declaration:
<?php
class Config {
public readonly string $databaseHost = 'localhost';
public readonly int $port = 3306;
}
$config = new Config();
echo $config->databaseHost; // Outputs: localhost
echo $config->port; // Outputs: 3306
// $config->databaseHost = '127.0.0.1'; // Error: Cannot modify readonly property Config::$databaseHost
In this case, the readonly properties are set with default values and can't be changed after the object is instantiated.
Readonly Properties with Private Access
Readonly properties can also be declared with private
or protected
visibility, which limits access and assignment even further.
<?php
class Order {
private readonly string $orderId;
private readonly float $totalAmount;
public function __construct(string $orderId, float $totalAmount) {
$this->orderId = $orderId;
$this->totalAmount = $totalAmount;
}
public function getOrderId(): string {
return $this->orderId;
}
public function getTotalAmount(): float {
return $this->totalAmount;
}
}
$order = new Order('ORD123', 99.99);
echo $order->getOrderId(); // Outputs: ORD123
echo $order->getTotalAmount(); // Outputs: 99.99
// The following will throw errors because $orderId and $totalAmount are private readonly properties:
// $order->orderId = 'ORD124'; // Error
// $order->totalAmount = 199.99; // Error
In this example:
- The readonly properties
orderId
andtotalAmount
areprivate
, making them accessible only within the class. - Public getter methods
getOrderId()
andgetTotalAmount()
allow safe access to these properties, but they remain immutable.
Use Cases for Readonly Properties
Readonly properties are especially useful in the following scenarios:
Value Objects
In Domain-Driven Design (DDD), Value Objects are immutable objects that represent a value without an identity. For example, a Currency
class that encapsulates a currency’s value and code should not allow changes after its creation.
<?php
class Currency {
public readonly string $code;
public readonly float $value;
public function __construct(string $code, float $value) {
$this->code = $code;
$this->value = $value;
}
}
$currency = new Currency('USD', 100.50);
echo $currency->code; // Outputs: USD
echo $currency->value; // Outputs: 100.5
// $currency->code = 'EUR'; // Error: Cannot modify readonly property Currency::$code
Immutable Configuration Classes
When dealing with configurations that shouldn't be modified during runtime, readonly properties help lock down values.
<?php
class AppConfig {
public readonly string $appName;
public readonly bool $debugMode;
public function __construct(string $appName, bool $debugMode) {
$this->appName = $appName;
$this->debugMode = $debugMode;
}
}
$config = new AppConfig('MyApp', true);
Ensuring Data Integrity
Readonly properties are an excellent tool for ensuring data integrity, especially when dealing with sensitive information, like user IDs or API keys, that should not change after initialization.
<?php
class ApiClient {
public readonly string $apiKey;
public function __construct(string $apiKey) {
$this->apiKey = $apiKey;
}
public function getApiKey(): string {
return $this->apiKey;
}
}
$client = new ApiClient('abc123xyz');
echo $client->getApiKey(); // Outputs: abc123xyz
// $client->apiKey = 'newKey'; // Error: Cannot modify readonly property ApiClient::$apiKey
Readonly Properties and Inheritance
Readonly properties behave consistently with PHP's inheritance model. If you inherit a class with readonly properties, you can use them just like any other property, but the readonly restriction still applies.
<?php
class ParentClass {
protected readonly string $parentProp;
public function __construct(string $parentProp) {
$this->parentProp = $parentProp;
}
}
class ChildClass extends ParentClass {
public readonly string $childProp;
public function __construct(string $parentProp, string $childProp) {
parent::__construct($parentProp);
$this->childProp = $childProp;
}
}
$child = new ChildClass('Parent Value', 'Child Value');
echo $child->parentProp; // Outputs: Parent Value
echo $child->childProp; // Outputs: Child Value
Conclusion
Readonly properties in PHP 8.1+ bring a much-needed enhancement to object-oriented programming by allowing for immutability in class properties. This feature simplifies the enforcement of data integrity and helps prevent unintended modifications to key values in your objects. By using readonly properties, you can write cleaner, safer, and more predictable code, especially in applications that rely on immutable data or fixed configurations.
To get the most out of this feature, remember to leverage readonly properties in situations where data should not change after initialization, such as in value objects, configuration classes, and when ensuring the security of sensitive data.
Readonly properties are another step toward making PHP a more robust and reliable language for modern application development.