Skip to content

PHP Tutorial Modern PHP Features

Readonly Properties

Lesson 225 of 369 2 min read By Deepak Paswan Updated Oct 5, 2026

A readonly property can be set once, and then it can never change. It arrived in PHP 8.1 and makes immutable objects easy.

index.php
PHP
<?php
class Order
{
    public function __construct(
        public readonly int $id,
        public readonly float $total,
    ) {}
}

$order = new Order(1042, 599.0);

echo $order->id . "\n";

try {
    $order->total = 1.0;
} catch (Error $e) {
    echo $e->getMessage();
}
Output
OUTPUT
1042
Cannot modify readonly property Order::$total

Because the property is public readonly, everyone can read it, but nobody can change it. You do not need a getter.

Rules

  1. Only typed properties can be readonly.
  2. The property can be written once, and only from inside the class.
  3. A readonly property cannot have a default value in its declaration (it is set in the constructor or another method).
  4. A readonly property cannot be unset() once set.
index.php
PHP
<?php
class Config
{
    public readonly array $values;

    public function __construct(array $values)
    {
        $this->values = $values;   // the first (and only) write
    }
}

$c = new Config(["debug" => true]);

try {
    $c->values["debug"] = false;
} catch (Error $e) {
    echo $e->getMessage();
}
Output
OUTPUT
Cannot modify readonly property Config::$values

Notice that even changing inside the array is blocked. A readonly array is truly fixed.

Objects inside are still changeable

readonly protects the property, not the object it points to. If the property holds an object, that object’s own properties can change.

index.php
PHP
<?php
class Counter
{
    public int $count = 0;
}

class Holder
{
    public function __construct(public readonly Counter $counter) {}
}

$h = new Holder(new Counter());
$h->counter->count = 5;     // allowed: it changes the inner object

echo $h->counter->count;
Output
OUTPUT
5

For full immutability, the inner objects must be readonly too.

Changing values: “with” methods

An immutable object cannot be edited, so you make a new copy with a different value. These methods are usually named with....

index.php
PHP
<?php
final class Money
{
    public function __construct(
        public readonly int $cents,
        public readonly string $currency = "INR",
    ) {}

    public function withCents(int $cents): static
    {
        return new static($cents, $this->currency);
    }
}

$a = new Money(500);
$b = $a->withCents(750);

echo $a->cents . " " . $b->cents;
Output
OUTPUT
500 750

Why use readonly

  • No surprises. A value cannot change behind your back.
  • Safe sharing. You can pass an object around freely.
  • Less code. No getters, no setters.

Cloning

clone copies a readonly object, but you cannot change the readonly properties of the copy afterwards (before PHP 8.3, not even inside __clone()). PHP 8.3 relaxed this slightly for deep copies inside __clone(). PHP 8.5 adds a clone form that accepts new values.

lightbulb
Use readonly by default
When you create a new class for data (an address, a money amount, a request), start with readonly properties. Remove readonly only for a property that really must change.