The new immutablephp/immutable package provides truly immutable value objects and an immutable value bag, along with base Immutable and ValueObject classes for your own objects. It helps to prevent against the oversights described by my earlier article Avoiding Quasi-Immutable Objects in PHP. (Of course, it cannot prevent you from deliberately adding your own mutable behaviors, or from using reflection to mutate an object from the outside. If you do those things, you get what you deserve.)
Its base Immutable class protects against common oversights in PHP regarding immutables:
final public function __set()and
final public function __unset()to prevent adding and mutating undefined properties.
final public function offsetSet()and
final public function offsetUnset()to prevent adding and mutating values via ArrayAccess.
It prevents multiple calls to
__construct()to re-initialize the object properties.
Further, the base ValueObject class
with() method checks the types of all incoming values to make sure they are themselves immutable. It does so via static methods on the Type class.
The Type class recognizes scalars and nulls as immutable. All other non-object values (such are resources and arrays) are rejected as mutable.
When it comes to objects, the Type class recognizes anything descended from Immutable as immutable, as well as DateTimeImmutable. To allow Type to recognize other immutable classes, call
Type::register() with a variadic list of fully-qualified class names that you want to treat as immutable.
There is also an immutable value Bag for an arbitrary collection of immutable values; it can be useful for immutable representations of JSON data.
If you need truly immutable objects for your PHP project, give immutablephp/immutable a try!
Read the Reddit commentary on this post here.