PHP Readonly Properties and Why Immutability Matters

PHP 8.1 added readonly properties, letting you enforce immutability at the language level — once set in the constructor, a readonly property can never be changed again, which eliminates a whole category of “who mutated this” bugs.

class Money {
    public function __construct(
        public readonly int $amountCents,
        public readonly string $currency
    ) {}

    public function add(Money $other): self {
        if ($this->currency !== $other->currency) {
            throw new InvalidArgumentException('Currency mismatch');
        }
        // Can't mutate $this->amountCents - must return a new instance
        return new self($this->amountCents + $other->amountCents, $this->currency);
    }
}

$price = new Money(1999, 'EUR');
// $price->amountCents = 500; // Fatal error: Cannot modify readonly property
$total = $price->add(new Money(500, 'EUR')); // returns a new Money instead

Immutable value objects like this are much easier to reason about in concurrent or long-lived contexts — you never have to wonder whether some distant piece of code changed the object out from under you.