One time I tweeted:
Modern object-oriented programming languages need support for immutable Value Objects. #DDD
The “DDD” in that tweet stands for Domain-Driven Design. There were several interesting responses to this tweet. Kevin Schroeder thought that it made a lot of sense but pointed out that “need” was a bit of a strong word. I should have instead said that this would be a “useful” feature. Matthew Weier O’Phinney shared an example of making an immutable object in PHP. Ralph Schindler suggested throwing an exception so as not to silently reject an attempt to modify the object’s state. Nicolas Bérard-Nault had a similar suggestion of implementing PHP’s __set magic method and throwing an exception so that new public attributes cannot be assigned and also not making any methods that change the state of the object. Giorgio Sironi suggested that PHP’s “private” keyword was all you needed to support immutable Value Objects.
The above suggestions are all useful when implementing immutable Value Objects in PHP. I would also add that you need to make the class “final” to truly guarantee that it’s immutable. This is so that someone can’t extend the class and add (or override) methods that change state (although I suppose if you made the __set method final and had it throw an exception that should do the trick since you wouldn’t be able to change any properties).
Regardless, all of these attempts to guarantee immutability miss the
point. I don’t need to make sure the class is immutable when its
defined, I need to know in my client code that it’s immutable. In other
words, I need a contract that says the object is immutable.
None of the above workarounds give you an explicit contract that the
object is immutable. Hopefully you’re working on a team where you trust
that if a teammate tells you that something is an immutable Value
Object, it is immutable. In fact, I wouldn’t normally bother doing any
of the above tricks to absolutely guarantee that the object is
immutable. This is because you still can’t tell by looking at the object
that it is immutable without inspecting its implementation. A built-in
language feature would be useful because it would provide an explicit
contract that the object is immutable.