Readonly Properties in PHP: Unveraenderlichkeit erzwingen
AI generated
<?php
8.4
PHP · Readonly Properties · Immutability
Readonly Properties in PHP
Unveraenderlichkeit auf Sprachebene erzwingen

Mutable Objekte sind eine der haeufigsten Quellen fuer schwer nachvollziehbare Bugs: Ein Wert aendert sich irgendwo im Aufrufgraphen, und niemand weiss mehr genau wo. Readonly Properties verlagern diese Garantie vom Konventions- ins Sprachlevel, seit PHP 8.1 fuer einzelne Properties, seit PHP 8.3 fuer ganze Klassen, und machen Unveraenderlichkeit zu einer Eigenschaft, die der Interpreter selbst durchsetzt statt nur zu dokumentieren.

13 Min. Lesezeit Readonly Properties · Readonly Classes · Immutability PHP 8.1 - 8.4

1. Warum Unveraenderlichkeit auf Sprachebene zaehlt

Mutable State ist einer der zuverlaessigsten Wege, um schwer reproduzierbare Bugs zu erzeugen. Ein Objekt wird an eine Methode uebergeben, irgendwo tief im Aufrufgraphen aendert eine Zeile Code eine Property, und der Aufrufer wundert sich Stunden spaeter, warum sein eigentlich unveraendertes Objekt ploetzlich andere Werte traegt. Vor PHP 8.1 gab es fuer dieses Problem nur Konventionen: private Properties, ein Getter ohne Setter, ein Docblock mit "immutable, do not modify". All das ist eine Bitte an andere Entwickler, keine Garantie des Compilers. Readonly Properties aendern das grundlegend, weil die Unveraenderlichkeit direkt im Typsystem der Sprache verankert wird.

Der Denkfehler, der ohne Readonly Properties haeufig passiert: Ein Value Object wie eine Geldsumme oder ein Datumsbereich wird als Referenz durch mehrere Schichten einer Anwendung gereicht, und irgendeine Schicht mutiert es "nur kurz", um es danach weiterzugeben. Das funktioniert so lange gut, bis zwei Codepfade dasselbe Objekt referenzieren und einer der beiden Pfade mit einem veraenderten Zustand rechnet, den der andere Pfad nie beabsichtigt hat. Solche Bugs sind notorisch schwer zu debuggen, weil der Fehler zeitlich und raeumlich weit vom Symptom entfernt auftreten kann.

Auch ausserhalb von Nebenlaeufigkeit im klassischen Sinn lohnt sich Unveraenderlichkeit: Ein Objekt, dessen Zustand nach der Konstruktion feststeht, ist einfacher zu verstehen, einfacher zu testen und einfacher im Code zu verfolgen, weil man beim Lesen einer Methode nicht mehr pruefen muss, ob sie irgendeine Property eines uebergebenen Objekts veraendert. Readonly Properties machen dieses Versprechen explizit und maschinell pruefbar, statt es dem Vertrauen in die Disziplin des Entwicklerteams zu ueberlassen.

2. Syntax und Grundregeln von readonly

Die Syntax von Readonly Properties ist bewusst minimal: Das Schluesselwort readonly wird vor dem Sichtbarkeitsmodifikator einer typisierten Property platziert, etwa public readonly string $email;. Eine zentrale Einschraenkung, die oft uebersehen wird: Eine readonly Property muss zwingend typisiert sein, ein readonly $value ohne Typ-Deklaration ist ein Parse-Fehler. Das ist konsistent mit dem generellen Ziel der Sprache, Typinformationen und Sprachgarantien eng zu verzahnen.

Eine readonly Property laesst sich genau einmal einen Wert zuweisen, danach ist jeder weitere Schreibversuch ein Error zur Laufzeit, kein stiller No-Op und kein Warning. Das gilt unabhaengig davon, ob der zweite Schreibversuch von innerhalb oder ausserhalb der Klasse kommt. Damit unterscheidet sich readonly fundamental von einer rein durch Sichtbarkeit geschuetzten Property: Eine private Property kann innerhalb der Klasse beliebig oft neu zugewiesen werden, eine readonly Property nicht, selbst nicht von der eigenen Klasse aus, nach der Erstzuweisung.

Der Fehlerklassenname ist bewusst spezifisch: Error, nicht TypeError oder ValueError, mit einer klaren Meldung wie "Cannot modify readonly property Foo::$bar". Diese Vorhersagbarkeit ist wichtig fuer den Umgang mit Readonly Properties in try/catch-Bloecken: Wer defensiv programmiert und eine erneute Zuweisung abfangen will, faengt gezielt Error, nicht die generische Throwable-Basis ohne weitere Differenzierung.


declare(strict_types=1);

final class EmailAddress
{
    // A readonly property must be typed - untyped readonly is a parse error
    public readonly string $value;

    public function __construct(string $value)
    {
        if (!str_contains($value, '@')) {
            throw new InvalidArgumentException('Invalid email address');
        }
        $this->value = $value; // first and only assignment
    }
}

$email = new EmailAddress('dev@mironsoft.de');
echo $email->value; // dev@mironsoft.de

try {
    $email->value = 'other@example.com'; // throws Error, even from outside
} catch (Error $e) {
    echo $e->getMessage(); // Cannot modify readonly property EmailAddress::$value
}

3. Initialisierung: nur einmal, nur aus dem deklarierenden Scope

Die Initialisierungsregel von Readonly Properties ist strenger als "nur einmal zuweisen": Der erste Schreibzugriff darf ausschliesslich aus dem Scope der Klasse erfolgen, die die Property deklariert hat. Das bedeutet konkret, dass selbst der Konstruktor einer Subklasse eine geerbte readonly Property der Elternklasse nicht direkt initialisieren kann, wenn diese bereits einen Wert erhalten hat, und dass Code ausserhalb der Klasse niemals der erste Schreibende sein darf, auch nicht auf eine noch uninitialisierte Property.

Wird eine typisierte Property gelesen, bevor sie initialisiert wurde, egal ob readonly oder nicht, wirft PHP einen Error mit einer Meldung ueber uninitialisierte typisierte Properties. Bei Readonly Properties kommt hinzu, dass dieser Zustand des "noch nicht initialisiert, aber bereits deklariert" tatsaechlich vorkommen kann, etwa wenn eine Property nicht im Konstruktor, sondern erst in einer spaeter aufgerufenen Methode befuellt wird. Das ist erlaubt, solange die Zuweisung aus dem deklarierenden Scope stammt und nur einmal geschieht, aber es verlangt Sorgfalt, damit ein Objekt nicht in einem unbrauchbaren Zwischenzustand an anderen Code weitergegeben wird.

Constructor Property Promotion ist der uebliche und empfohlene Weg, Readonly Properties zu initialisieren, weil Deklaration, Typisierung und Erstzuweisung in einer einzigen Zeile im Konstruktor zusammenfallen. Das reduziert das Risiko, eine Property versehentlich unbefuellt zu lassen, auf ein Minimum, weil der Wert direkt als Konstruktor-Parameter erzwungen wird und PHP die Zuweisung automatisch vornimmt.


declare(strict_types=1);

final class Money
{
    // Constructor property promotion combines declaration and first assignment
    public function __construct(
        public readonly int $amountInCents,
        public readonly string $currency,
    ) {
        if ($amountInCents < 0) {
            throw new InvalidArgumentException('Amount cannot be negative');
        }
    }

    public function add(Money $other): self
    {
        if ($this->currency !== $other->currency) {
            throw new InvalidArgumentException('Currency mismatch');
        }
        // Cannot mutate $this - a new instance is returned instead
        return new self($this->amountInCents + $other->amountInCents, $this->currency);
    }
}

$price = new Money(1999, 'EUR');
$shipping = new Money(495, 'EUR');
$total = $price->add($shipping); // new Money instance, both originals untouched

4. Readonly Classes seit PHP 8.3

PHP 8.3 fuehrt readonly class ein, um das wiederholte Ausschreiben von readonly vor jeder einzelnen Property zu ersparen. Wird eine Klasse als Ganzes mit readonly class Money { ... } deklariert, gelten automatisch alle deklarierten Properties der Klasse als Readonly Properties, ohne dass das Schluesselwort pro Property wiederholt werden muss. Das ist besonders bei Value Objects mit vielen Feldern eine spuerbare Vereinfachung und reduziert visuelles Rauschen im Code.

Eine wichtige Einschraenkung: Eine readonly class darf ausschliesslich typisierte Properties enthalten, dieselbe Regel wie bei einer einzelnen readonly Property, nur jetzt fuer die gesamte Klasse durchgesetzt. Zudem kann eine readonly class nicht nachtraeglich in eine "teilweise mutable" Klasse verwandelt werden, indem eine einzelne Property explizit als nicht-readonly markiert wird, dieses Konzept existiert schlicht nicht. Wer eine Mischung aus veraenderlichen und unveraenderlichen Properties braucht, muss auf die Deklaration pro einzelner Property zurueckgreifen, statt die Klasse als Ganzes readonly zu machen.

Ein zweiter wichtiger Effekt von readonly class: Eine Subklasse einer readonly Klasse muss ebenfalls readonly sein. Es ist nicht moeglich, von einer readonly class zu erben und die abgeleitete Klasse mutable zu machen. Diese Regel verhindert, dass die Unveraenderlichkeitsgarantie durch Vererbung unbemerkt unterlaufen wird, was sonst ein subtiler Bruch der Erwartungen waere, die ein Aufrufer an den Basistyp stellt.


declare(strict_types=1);

// Every property in this class is implicitly readonly
readonly class DateRange
{
    public function __construct(
        public DateTimeImmutable $start,
        public DateTimeImmutable $end,
    ) {
        if ($start > $end) {
            throw new InvalidArgumentException('Start must be before end');
        }
    }

    public function containsDate(DateTimeImmutable $date): bool
    {
        return $date >= $this->start && $date <= $this->end;
    }

    public function durationInDays(): int
    {
        return $this->start->diff($this->end)->days;
    }
}

$range = new DateRange(
    new DateTimeImmutable('2026-01-01'),
    new DateTimeImmutable('2026-01-31'),
);

echo $range->durationInDays(); // 30

5. Clone-Verhalten bei readonly Objekten

Ein haeufiges Missverstaendnis bei Readonly Properties ist die Annahme, ein Objekt liesse sich niemals modifizieren, auch nicht durch Cloning. Tatsaechlich war es bis einschliesslich PHP 8.2 nicht erlaubt, in einer __clone()-Methode readonly Properties neu zuzuweisen, weil das Klonen selbst als "ausserhalb des urspruenglichen Initialisierungsscopes" galt. Diese Einschraenkung war fuer viele praktische with-Pattern-Implementierungen hinderlich, weil sich neue Werte nur ueber vollstaendig neue Konstruktor-Aufrufe erzeugen liessen, selbst wenn nur eine einzige Property geaendert werden sollte.

Seit PHP 8.3 erlaubt die Sprache das Neuinitialisieren von Readonly Properties innerhalb von __clone(), solange die Zuweisung innerhalb der deklarierenden Klasse erfolgt und die Property zu diesem Zeitpunkt bereits initialisiert ist. Das oeffnet einen sauberen Weg, um innerhalb eines Klons gezielt einzelne Werte zu aendern, ohne den gesamten Konstruktor mit all seinen Validierungen erneut durchlaufen zu muessen. Das eigentliche Objekt, von dem geklont wird, bleibt dabei vollstaendig unberuehrt, nur die neue Kopie erhaelt die geaenderten Werte.

Wichtig ist die Abgrenzung: Diese Faehigkeit gilt ausschliesslich fuer das Neuzuweisen innerhalb von __clone() selbst, nicht fuer beliebigen Code ausserhalb der Klasse nach einem Klonvorgang. Ein Aufrufer, der clone $object schreibt und danach versucht, eine Property des Klons direkt zu setzen, erhaelt weiterhin den bekannten Error. Die Kontrolle ueber die Mutation im Klon bleibt vollstaendig bei der Klasse selbst, was mit dem Grundprinzip von Readonly Properties konsistent ist: Aenderungen sind nur innerhalb des deklarierenden Scopes moeglich, niemals von aussen.


declare(strict_types=1);

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

    // Since PHP 8.3: readonly properties may be reassigned inside __clone()
    public function withAmount(int $newAmountInCents): self
    {
        $clone = clone $this;
        // This reassignment is only legal inside __clone(), never from outside
        return $clone;
    }

    public function __clone(): void
    {
        // Example: normalize or adjust a value during cloning if needed
    }
}

6. Immutable Value Objects und das with-Pattern

Weil Readonly Properties jede direkte Mutation nach der Initialisierung verbieten, braucht ein unveraenderliches Value Object einen anderen Mechanismus, um "geaenderte" Zustaende auszudruecken: Statt eine bestehende Instanz zu veraendern, wird eine neue Instanz mit den gewuenschten Werten erzeugt, waehrend die urspruengliche Instanz vollstaendig unangetastet bleibt. Dieses Muster ist unter dem Namen with-Pattern bekannt, benannt nach der ueblichen Methodenkonvention withX(), etwa withAmount() oder withStatus().

Bibliotheken wie DateTimeImmutable haben dieses Muster schon vor Readonly Properties etabliert: $date->modify('+1 day') veraendert nicht das urspruengliche Objekt, sondern liefert ein neues zurueck. Mit readonly Properties laesst sich dasselbe Verhalten fuer eigene Value Objects konsistent nachbauen, ohne auf interne Tricks angewiesen zu sein, weil der Sprachkern selbst verhindert, dass eine with-Methode versehentlich $this statt einer Kopie zurueckgibt und mutiert.

Der praktische Vorteil zeigt sich besonders in nebenlaeufigem oder verteiltem Code, in Warteschlangen-Konsumenten oder in Situationen, in denen ein Objekt an mehrere Stellen im Code weitergereicht wird: Da Readonly Properties jede Mutation ausschliessen, kann keine dieser Stellen das Objekt fuer alle anderen unbemerkt veraendern. Jede Codepassage, die eine Aenderung will, muss explizit eine neue Instanz anfordern und diese explizit weiterreichen, was Datenfluesse im Code deutlich nachvollziehbarer macht als implizite Mutation an entfernter Stelle.


declare(strict_types=1);

readonly class OrderLine
{
    public function __construct(
        public string $sku,
        public int $quantity,
        public int $unitPriceInCents,
    ) {
    }

    // "with" methods return a new instance instead of mutating the current one
    public function withQuantity(int $quantity): self
    {
        return new self($this->sku, $quantity, $this->unitPriceInCents);
    }

    public function totalInCents(): int
    {
        return $this->quantity * $this->unitPriceInCents;
    }
}

$line = new OrderLine('SKU-123', 2, 1999);
$updatedLine = $line->withQuantity(5);

echo $line->quantity;        // 2 - the original instance is untouched
echo $updatedLine->quantity; // 5 - a distinct new instance

7. Readonly vs. const und final

Ein wiederkehrendes Missverstaendnis besteht darin, Readonly Properties mit Klassenkonstanten oder mit final gleichzusetzen, obwohl alle drei unterschiedliche Probleme loesen. Eine Klassenkonstante wird zur Compile-Zeit festgelegt, ist an die Klasse selbst gebunden, nicht an eine Instanz, und ihr Wert ist fuer alle Instanzen identisch. Eine readonly Property dagegen wird zur Laufzeit gesetzt, meist im Konstruktor, und kann fuer jede Instanz einen anderen Wert tragen. Wer versucht, mit Konstanten individuelle Objektdaten wie eine E-Mail-Adresse oder einen Bestellwert abzubilden, stoesst schnell an eine Grenze, die Readonly Properties gar nicht kennen.

Das Schluesselwort final wiederum betrifft Vererbung, nicht Veraenderlichkeit: Eine final Methode kann nicht ueberschrieben werden, eine final Klasse kann nicht erweitert werden, aber beides sagt nichts darueber aus, ob eine Instanzeigenschaft nach der Konstruktion veraendert werden kann. Es ist vollkommen ueblich und sinnvoll, final class mit Readonly Properties zu kombinieren, etwa bei Value Objects, weil beide Eigenschaften dasselbe Ziel unterstuetzen: ein vorhersehbares, nicht heimlich veraendertes Verhalten, einmal bei der Vererbungshierarchie, einmal beim Objektzustand.

In der Praxis ergaenzen sich alle drei Mechanismen: const fuer Werte, die unabhaengig von einer konkreten Instanz und zur Compile-Zeit bekannt sind, etwa ein Steuersatz oder ein Wechselkurs-Rundungsfaktor. Readonly Properties fuer instanzspezifische Daten, die nach der Erzeugung stabil bleiben sollen. final fuer die Klasse oder Methode selbst, wenn Erweiterbarkeit bewusst ausgeschlossen werden soll. Wer diese drei Werkzeuge klar auseinanderhaelt, vermeidet Verwirrung darueber, welches Sprachfeature welches konkrete Problem adressiert.

Mechanismus Bindung Zeitpunkt der Festlegung Loest welches Problem
const Klasse, geteilt ueber alle Instanzen Compile-Zeit Feste, klassenweite Werte
Readonly Properties Instanz, individueller Wert Laufzeit, meist im Konstruktor Unveraenderlicher Instanzzustand
final Klasse oder Methode Deklaration Vererbung/Ueberschreiben unterbinden
private ohne readonly Instanz, mutable Beliebig oft zur Laufzeit Kapselung ohne Unveraenderlichkeit

8. Readonly und Vererbung

Vererbung und Readonly Properties haben mehrere Sonderregeln, die bei der Modellierung von Klassenhierarchien beachtet werden muessen. Eine Subklasse kann eine geerbte readonly Property nicht erneut als non-readonly deklarieren, um die Einschraenkung wieder aufzuheben, das waere ein Bruch des Vertrags, den die Basisklasse gegenueber jedem Konsumenten eingeht. Ebenso kann eine Subklasse eine bereits typisierte readonly Property der Basisklasse nicht mit einem inkompatiblen Typ neu deklarieren, dieselben Kovarianzregeln wie bei normalen typisierten Properties gelten unveraendert weiter.

Bei geerbten Konstruktoren ist besondere Vorsicht geboten: Wenn eine Subklasse ihren eigenen Konstruktor definiert und dabei eine readonly Property der Elternklasse zusaetzlich initialisieren will, muss diese Initialisierung ueber einen Aufruf von parent::__construct() erfolgen, wenn die Property in der Elternklasse deklariert wurde, denn nur der deklarierende Scope darf die Erstzuweisung vornehmen. Ein direkter Zugriff wie $this->parentProperty = $value; im Konstruktor der Subklasse ist fuer eine in der Elternklasse deklarierte readonly Property nicht erlaubt, selbst wenn die Property als protected sichtbar ist.

Bei abstrakten Klassen und Interfaces gilt: Ein Interface kann selbst keine Properties deklarieren, aber eine abstrakte Klasse kann Readonly Properties vordeklarieren, die konkrete Subklassen dann im eigenen Konstruktor befuellen muessen. Dieses Muster ist nuetzlich, um eine gemeinsame, unveraenderliche Basisstruktur zu erzwingen, waehrend die konkrete Initialisierungslogik den jeweiligen Subklassen ueberlassen bleibt, etwa bei einer Familie von Event-Klassen, die alle einen readonly Zeitstempel tragen, aber unterschiedliche Payload-Typen haben.


declare(strict_types=1);

abstract class DomainEvent
{
    public function __construct(
        public readonly DateTimeImmutable $occurredAt,
    ) {
    }
}

final class OrderPlaced extends DomainEvent
{
    public function __construct(
        public readonly string $orderId,
        DateTimeImmutable $occurredAt,
    ) {
        // Must delegate initialization of the parent's readonly property
        parent::__construct($occurredAt);
    }
}

$event = new OrderPlaced('ORD-4711', new DateTimeImmutable());
echo $event->occurredAt->format('Y-m-d H:i:s');

9. Typische Fehler und Fallstricke

Der haeufigste Fallstrick bei Readonly Properties ist die Annahme, dass ein Objekt vollstaendig unveraenderlich ist, sobald seine Properties readonly sind. Das gilt nur fuer die Referenz selbst, nicht fuer den referenzierten Inhalt: Ist eine readonly Property ein Array oder ein mutable Objekt, verbietet readonly lediglich, die Property mit einem komplett neuen Array oder Objekt zu ueberschreiben. Der Inhalt eines readonly Arrays kann trotzdem veraendert werden, indem einzelne Elemente direkt angesprochen werden, etwa $order->items[] = $newItem;, was in vielen Faellen eine ungewollte Luecke in der beabsichtigten Unveraenderlichkeit oeffnet.

Ein zweiter Fallstrick betrifft Reflection: Die PHP-Reflection-API kann mit ReflectionProperty::setValue() und expliziter Aufhebung der Zugriffsbeschraenkung dennoch auf readonly Properties schreibend zugreifen, sofern der aufrufende Code die entsprechenden Rechte besitzt. Readonly Properties sind daher eine starke, aber keine absolute Sicherheitsgarantie gegen jede Form von Manipulation, sie schuetzen zuverlaessig vor versehentlicher Mutation im normalen Anwendungscode, nicht aber vor bewusster Umgehung ueber Reflection oder Serialisierungs-Interna.

Ein dritter, subtilerer Fallstrick betrifft unserialize() und aehnliche Mechanismen: Objekte, die aus einem serialisierten String oder aus var_export()-Ausgaben rekonstruiert werden, koennen unter Umstaenden Wege finden, readonly Properties ausserhalb des normalen Konstruktor-Flusses zu setzen, abhaengig von der PHP-Version und dem verwendeten Serialisierungsformat. Wer Readonly Properties in Objekten einsetzt, die serialisiert und wiederhergestellt werden, etwa in Session-Daten oder Message-Queue-Payloads, sollte das konkrete Verhalten der eingesetzten PHP-Version testen, statt sich blind auf die Konstruktor-Garantie zu verlassen.

10. Zusammenfassung

Readonly Properties verlagern Unveraenderlichkeit von einer Konvention in eine vom Sprachkern erzwungene Garantie. Die Syntax ist minimal, das Schluesselwort readonly vor einer typisierten Property, aber die Regeln dahinter sind praezise: genau eine Zuweisung, ausschliesslich aus dem deklarierenden Scope, mit einem klaren Error bei jedem weiteren Schreibversuch. Readonly Classes seit PHP 8.3 machen diese Garantie fuer ganze Klassen mit einem einzigen Schluesselwort statt pro Property nutzbar, und das erweiterte Clone-Verhalten seit PHP 8.3 erlaubt kontrollierte Neuinitialisierung innerhalb von __clone(), ohne die Garantie von aussen aufzuweichen.

Das with-Pattern ist der natuerliche Begleiter von Readonly Properties: Statt ein Objekt zu mutieren, entsteht bei jeder Aenderung eine neue Instanz, waehrend die urspruengliche unangetastet bleibt. Wichtig bleibt das Bewusstsein fuer die Grenzen: readonly schuetzt die Referenz einer Property, nicht automatisch den Inhalt mutabler Arrays oder Objekte darin, und Reflection kann die Garantie unter bestimmten Bedingungen umgehen. Wer diese Grenzen kennt und Readonly Properties gezielt fuer Value Objects, DTOs und Domain Events einsetzt, gewinnt Code, der beim Lesen weniger Ueberraschungen bereithaelt und dessen Zustand jederzeit nachvollziehbar bleibt.

Readonly Properties: das Wichtigste auf einen Blick

Syntax und Regel

readonly vor einer typisierten Property, genau eine Zuweisung nur aus dem deklarierenden Scope, sonst Error.

Readonly Classes (8.3)

readonly class macht alle Properties readonly, Subklassen muessen ebenfalls readonly sein.

with-Pattern

Aenderungen erzeugen neue Instanzen statt zu mutieren, das Original bleibt unberuehrt.

Grenzen kennen

Schuetzt die Referenz, nicht den Inhalt mutabler Arrays. Reflection kann die Garantie umgehen.

11. FAQ: Readonly Properties in PHP

1Was sind Readonly Properties und seit welcher Version gibt es sie?
Seit PHP 8.1 verfuegbar, erlauben genau eine Wertzuweisung pro Property, ausschliesslich aus dem deklarierenden Scope. Jeder weitere Schreibversuch loest einen Error aus.
2Muss eine readonly Property immer typisiert sein?
Ja. Eine readonly Property ohne Typ-Deklaration ist ein Parse-Fehler. readonly setzt zwingend eine typisierte Property voraus.
3Was ist eine Readonly Class?
Seit PHP 8.3 markiert readonly class alle Properties automatisch als readonly. Subklassen einer readonly Klasse muessen ebenfalls readonly sein.
4Kann ich eine readonly Property in __clone() aendern?
Seit PHP 8.3 ja, innerhalb von __clone() duerfen readonly Properties neu zugewiesen werden. Von aussen bleibt jede Aenderung weiterhin verboten.
5Was ist der Unterschied zwischen readonly und const?
const legt einen zur Compile-Zeit festen, klassenweit geteilten Wert fest. Readonly Properties werden zur Laufzeit gesetzt und koennen pro Instanz unterschiedlich sein.
6Schuetzt readonly auch den Inhalt eines Arrays?
Nein. readonly verbietet nur das Ueberschreiben mit einem neuen Array. Einzelne Elemente koennen weiterhin direkt veraendert werden, etwa mit $obj->items[] = $x.
7Was ist das with-Pattern?
Statt zu mutieren, erzeugt eine withX()-Methode eine neue Instanz mit geaendertem Wert, das Original bleibt unveraendert. Bekannt aus DateTimeImmutable.
8Kann eine Subklasse eine geerbte readonly Property selbst initialisieren?
Nein, direkt nicht. Die Initialisierung muss ueber parent::__construct() erfolgen, weil nur der deklarierende Scope die Erstzuweisung vornehmen darf.
9Kann Reflection readonly Properties umgehen?
Ja, unter bestimmten Bedingungen kann die Reflection-API dennoch schreibend zugreifen. Die Garantie schuetzt vor versehentlicher Mutation, nicht vor bewusster Umgehung.
10Readonly class oder einzelne readonly Properties?
Bei Value Objects mit durchgehend unveraenderlichen Properties ist readonly class kompakter. Bei Mischung aus veraenderlichen und unveraenderlichen Properties muessen einzelne markiert werden.

Mironsoft

PHP Code-Reviews, Modernisierung und Immutability-Patterns

Mutable State sorgt fuer schwer nachvollziehbare Bugs?

Wir pruefen bestehende PHP-Codebasen auf mutable Value Objects und fuehren gezielt Readonly Properties, Readonly Classes und das with-Pattern ein, damit Objektzustand vorhersehbar bleibt und Datenfluesse nachvollziehbar sind.

Code-Review

Analyse bestehender Value Objects und DTOs auf Migrationspotenzial zu Readonly Properties

Modernisierung

Einfuehrung von Readonly Classes und dem with-Pattern fuer bestehende Domain-Modelle

Immutability-Strategie

Klare Trennung von Value Objects, Entities und mutable Zustand im gesamten Anwendungskern