readonly Properties

A readonly property (PHP 8.1) is written once, inside the class, and never again. It must be typed and cannot have a default, so it is set in the constructor, usually by promotion (Subsection 4.9.4). Since 8.4 a public readonly property is implicitly protected(set), so a subclass may initialize it.

A readonly SKU, and the object inside a readonly property that stays mutablePHP
<?php
final class Product {
  public function __construct(
    public readonly string $sku, public readonly ArrayObject $tags) {}
}
$p = new Product('BK-101', new ArrayObject(['php']));
$p->tags[] = 'lamp';                               // the property is fixed, the object is not
echo $p->sku, ' ', implode(',', (array) $p->tags), "\n";
try { $p->sku = 'BK-999'; } catch (Error $e) { echo $e->getMessage(), "\n"; }
Output
BK-101 php,lamp
Cannot modify readonly property Product::$sku

readonly fixes which value the property holds, not what happens inside it: the ArrayObject still accepts appends. For real immutability, hold scalars, enums and immutable objects such as DateTimeImmutable.