The Readonly Trap — PHP Value Objects & DDD Aggregates
readonly tells PHP a property can't be reassigned. It says nothing about whether two values are equal, or whether what's inside stays immutable. A full booking aggregate shows exactly where that gap bites. Every PHP DDD tutorial reaches the same beat: make your Value Object a final readonly class , validate in the constructor, done, immutability achieved. That's not wrong. It's incomplete in a…
The Readonly Trap — PHP Value Objects & DDD Aggregates
In PHP, the readonly keyword instructs the language that a property cannot be reassigned after construction. However, this does not guarantee that two values are equal or that the contents of a Value Object remain immutable. A full booking aggregate in PHP demonstrates how readonly alone falls short in certain scenarios.
A small hotel booking domain serves as an example of a proper implementation. The booking aggregate root, named Booking, contains a child Entity with its own identity and lifecycle, as well as four Value Objects responsible for the actual work. One business rule is enforced: cancelling a reservation less than 48 hours before check-in incurs a penalty charge, and only the aggregate root can handle this process.
The DateRange Value Object determines the duration of a stay and checks for overlaps with other date ranges. It ensures that check-out is after check-in and provides methods to compare with other DateRange instances. The equality method checks if both the start and end dates are identical.
Currency, an enum in PHP, defines the available currency codes, such as EUR and USD. This ensures that only valid currency codes are used within the system.
The Money Value Object represents monetary values, encapsulating cents and the associated currency. It provides methods for adding amounts, calculating percentages, and comparing Money instances. The equality comparison considers both the cents and currency properties.
When using readonly, Value Objects maintain their immutability within the scope of the file they are defined in. However, when these objects are passed around or stored in collections, deduplication or comparison becomes a challenge. Readonly does not enforce equality or immutability in these broader contexts.
To overcome these limitations, the article suggests maintaining separate contracts for equality and immutability. While readonly ensures that a property cannot be reassigned, additional logic is needed to enforce equality and immutability when Value Objects are used in a broader system, such as in collections or during comparisons.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.