Seit PHP 7.4 lassen sich Klasseneigenschaften direkt mit einer Typdeklaration versehen. Was zuvor nur für Funktionsparameter und Rückgabewerte möglich war, gilt nun auch für Properties. Dadurch erkennt PHP bereits bei der Zuweisung, ob ein Wert dem erwarteten Typ entspricht, und wirft andernfalls einen Fehler. Dieses Tutorial erklärt die Syntax von Typed Properties, zeigt die unterstützten Typen und geht auf Besonderheiten wie den „uninitialized“ Zustand, Nullable Properties, statische Properties und Constructor Promotion ein.

Los geht es mit der grundlegenden Frage, was Typed Properties sind und wie sie sich von den bisherigen untypisierten Eigenschaften unterscheiden.
Was sind Typed Properties?
Typed Properties ermöglichen es, den Datentyp einer Klasseneigenschaft direkt in der Deklaration anzugeben. Vor PHP 7.4 konnte der Typ einer Property nur über DocBlock Kommentare dokumentiert werden, was jedoch keinerlei Laufzeitprüfung bewirkte. Mit der Einführung von Typed Properties prüft PHP bei jeder Zuweisung automatisch, ob der Wert zum deklarierten Typ passt.
<?php
class Benutzer
{
public int $id;
public string $name;
public string $email;
public bool $aktiv = true;
}
$benutzer = new Benutzer();
$benutzer->id = 1;
$benutzer->name = 'Anna';
$benutzer->email = 'anna@beispiel.de';
echo $benutzer->name;
/* Anna */
Die Property $id akzeptiert ausschließlich Ganzzahlen, $name und $email ausschließlich Strings und $aktiv ausschließlich Booleans. Wird ein Wert mit einem inkompatiblen Typ zugewiesen, löst PHP einen TypeError aus. Die Property $aktiv besitzt zusätzlich den Standardwert true, sodass sie nicht zwingend manuell gesetzt werden muss.
Unterstützte Typen
PHP unterstützt eine breite Palette an Typen für Properties. Die folgende Übersicht zeigt alle verfügbaren Kategorien und ihre jeweiligen Typen.
flowchart TD
A["Typed Properties"] --> B["Eingebaute Typen"]
A --> C["Klassen und Interfaces"]
B --> D["Skalare Typen
int, float, string, bool"]
B --> E["Zusammengesetzte Typen
array, object, iterable"]
B --> F["Spezielle Typen
self, parent, mixed, null"]
Erlaubt sind alle skalaren Typen (int, float, string, bool), zusammengesetzte Typen (array, object, iterable), Klassen und Interfaces sowie die speziellen Typen self, parent und ab PHP 8.0 auch mixed. Der Typ void ist für Properties ausdrücklich nicht erlaubt, da er nur als Rückgabetyp von Funktionen sinnvoll ist. Ab PHP 8.0 stehen zusätzlich Union Types zur Verfügung, etwa int|string, und ab PHP 8.1 Intersection Types wie Countable&Iterator.
<?php
class Konfiguration
{
public string $name;
public array $optionen = [];
public float $version = 1.0;
public object $logger;
public self $elternKonfiguration;
}
$config = new Konfiguration();
$config->name = 'Hauptkonfiguration';
$config->optionen = ['debug' => true, 'cache' => false];
$config->version = 2.5;
echo $config->name;
/* Hauptkonfiguration */
Die Property $optionen nutzt den Typ array und besitzt ein leeres Array als Standardwert. Die Property $elternKonfiguration verwendet self und akzeptiert damit nur Instanzen derselben Klasse. Jeder Versuch, einen Wert mit einem anderen Typ zuzuweisen, führt zu einem Fehler.
Initialisierung und der „uninitialized“ Zustand
Eine der wichtigsten Besonderheiten von Typed Properties ist der Zustand „uninitialized“. Eine typisierte Property ohne Standardwert befindet sich nach der Objekterstellung in diesem speziellen Zustand. Sie ist weder null noch hat sie einen Wert. Jeder Lesezugriff auf eine uninitialisierte Property löst einen Fehler aus.
<?php
class Artikel
{
public string $titel;
public float $preis;
}
$artikel = new Artikel();
/* Error: Typed property Artikel::$titel must not be
accessed before initialization */
echo $artikel->titel;
Dieses Verhalten unterscheidet sich grundlegend von untypisierten Properties, die standardmäßig den Wert null tragen. Die Funktion isset() gibt für uninitialisierte Typed Properties false zurück. Um den Fehler zu vermeiden, muss die Property entweder einen Standardwert erhalten oder im Konstruktor gesetzt werden. Gerade bei Klassen mit vielen Properties empfiehlt sich ein Konstruktor, der alle Pflichtfelder entgegennimmt und damit sicherstellt, dass kein Feld uninitialisiert bleibt. In der Praxis bedeutet das, dass Typed Properties eine bewusstere Gestaltung von Klassen erzwingen. Jede Property muss entweder im Konstruktor initialisiert oder mit einem sinnvollen Standardwert versehen werden, bevor sie gelesen werden darf.
Das folgende Diagramm zeigt den Lebenszyklus einer typisierten Property vom Moment der Deklaration bis zur Verwendung.
stateDiagram-v2
[*] --> Uninitialized : Property deklariert
Uninitialized --> Initialized : Wert zugewiesen
Uninitialized --> Error : Lesezugriff
Initialized --> Initialized : Neuer Wert zugewiesen
Initialized --> Null : null-Zuweisung erlaubt
Null --> Initialized : Neuer Wert zugewiesen
Wie das Diagramm verdeutlicht, gibt es keinen direkten Weg von „uninitialized“ zu einem gültigen Lesezugriff. Erst nach einer expliziten Wertzuweisung wechselt die Property in den Zustand „Initialized“ und kann sicher gelesen werden.
Nullable Properties
Wenn eine Property den Wert null annehmen darf, wird dem Typ ein Fragezeichen vorangestellt. Dadurch akzeptiert die Property sowohl den deklarierten Typ als auch null. Wichtig ist dabei, dass eine Nullable Property trotzdem nicht automatisch mit null initialisiert wird. Der Standardwert muss explizit angegeben werden.
<?php
class Profil
{
public string $name;
public ?string $biografie = null;
public ?string $webseite = null;
public function __construct(string $name)
{
$this->name = $name;
}
}
$profil = new Profil('Ben');
echo $profil->name;
/* Ben */
var_dump($profil->biografie);
/* NULL */
$profil->biografie = 'Softwareentwickler aus Berlin';
echo $profil->biografie;
/* Softwareentwickler aus Berlin */
Die Properties $biografie und $webseite sind als ?string deklariert und erhalten den Standardwert null. Dadurch können sie gelesen werden, ohne dass ein Fehler auftritt. Ohne die explizite Zuweisung von = null wären sie trotz des Fragezeichens im Zustand „uninitialized“ und ein Lesezugriff würde fehlschlagen. Der Unterschied zwischen „uninitialized“ und null ist daher zentral für das Verständnis von Typed Properties.
Statische Typed Properties
Auch statische Properties lassen sich mit einem Typ versehen. Die Typdeklaration steht dabei nach dem Sichtbarkeitsmodifikator und dem Schlüsselwort static.
<?php
class Zaehler
{
public static int $anzahl = 0;
public static string $letztesObjekt = '';
public function __construct(string $name)
{
self::$anzahl++;
self::$letztesObjekt = $name;
}
}
new Zaehler('Erster');
new Zaehler('Zweiter');
new Zaehler('Dritter');
echo Zaehler::$anzahl;
/* 3 */
echo Zaehler::$letztesObjekt;
/* Dritter */
Die statische Property $anzahl zählt die erstellten Instanzen, während $letztesObjekt den Namen der zuletzt erstellten Instanz speichert. Beide Properties profitieren von der Typdeklaration, da versehentliche Zuweisungen mit einem falschen Typ sofort erkannt werden. Statische Typed Properties eignen sich besonders für Konfigurationswerte, Singleton Instanzen und Zähler, bei denen ein konsistenter Typ über alle Zugriffe hinweg gewährleistet sein muss.
Typed Properties und Vererbung
Bei der Vererbung gelten strenge Regeln für Typed Properties. Eine Kindklasse darf den Typ einer geerbten Property nicht ändern. Der Typ muss exakt mit dem der Elternklasse übereinstimmen.
<?php
class Fahrzeug
{
public string $marke;
public int $baujahr;
public float $kilometerstand = 0.0;
}
class Elektroauto extends Fahrzeug
{
public int $akkuKapazitaet;
public float $reichweite;
public function __construct(
string $marke,
int $baujahr,
int $akkuKapazitaet,
float $reichweite
) {
$this->marke = $marke;
$this->baujahr = $baujahr;
$this->akkuKapazitaet = $akkuKapazitaet;
$this->reichweite = $reichweite;
}
}
$auto = new Elektroauto('Tesla', 2024, 75, 450.0);
echo $auto->marke;
/* Tesla */
echo $auto->akkuKapazitaet;
/* 75 */
Die Klasse Elektroauto erbt die Properties $marke, $baujahr und $kilometerstand von Fahrzeug und fügt eigene typisierte Properties hinzu. Ein Versuch, den Typ von $marke in der Kindklasse etwa auf int zu ändern, würde zu einem fatalen Fehler führen. Diese Einschränkung stellt sicher, dass Code, der mit der Elternklasse arbeitet, auch mit Instanzen der Kindklasse zuverlässig funktioniert.
Strict Types und Typed Properties
Ohne die Anweisung declare(strict_types=1) versucht PHP, zugewiesene Werte automatisch in den deklarierten Typ zu konvertieren. Ein String wie "42" wird bei der Zuweisung an eine int Property stillschweigend in die Zahl 42 umgewandelt. Mit aktivierten Strict Types wird diese automatische Konvertierung unterbunden und jede Typabweichung führt zu einem TypeError.
<?php
declare(strict_types=1);
class Produkt
{
public int $bestand;
public float $preis;
public string $name;
}
$produkt = new Produkt();
$produkt->name = 'Widget';
$produkt->preis = 9.99;
$produkt->bestand = 50;
/* TypeError: Ohne strict_types wuerde "50" akzeptiert */
/* $produkt->bestand = "50"; */
echo $produkt->bestand;
/* 50 */
Die aktivierte strikte Typisierung erhöht die Zuverlässigkeit des Codes erheblich. Fehler werden frühzeitig erkannt, statt stillschweigend durch Typkonvertierung verborgen zu werden. In professionellen Projekten empfiehlt es sich, declare(strict_types=1) in jeder PHP Datei zu verwenden.
Constructor Promotion (ab PHP 8.0)
Ab PHP 8.0 bietet Constructor Promotion eine kompakte Möglichkeit, Typed Properties direkt in der Konstruktorsignatur zu deklarieren und zu initialisieren. Dadurch entfällt die separate Deklaration und die manuelle Zuweisung im Konstruktorkörper.
<?php
class Produkt
{
public function __construct(
public readonly string $name,
public readonly float $preis,
public readonly int $bestand = 0,
public readonly ?string $beschreibung = null
) {}
}
$p = new Produkt('Widget', 9.99, 25);
echo $p->name;
/* Widget */
echo $p->preis;
/* 9.99 */
echo $p->bestand;
/* 25 */
var_dump($p->beschreibung);
/* NULL */
Durch das Schlüsselwort readonly (ab PHP 8.1) wird zusätzlich sichergestellt, dass die Properties nach der Initialisierung nicht mehr verändert werden können. Constructor Promotion reduziert die Menge an Boilerplate Code erheblich und macht Klassen deutlich übersichtlicher.
Warum Typed Properties verwenden?
Es gibt mehrere gewichtige Gründe, Typed Properties in PHP Projekten einzusetzen. An erster Stelle steht die erhöhte Codequalität. Typfehler werden nicht mehr erst zur Laufzeit in der Geschäftslogik sichtbar, sondern bereits bei der Zuweisung abgefangen. Das spart Debugging Zeit und reduziert die Fehleranfälligkeit. Darüber hinaus verbessern Typed Properties die Lesbarkeit des Codes erheblich. Andere Entwickler erkennen sofort, welche Datentypen eine Klasse erwartet, ohne zusätzliche Dokumentation lesen zu müssen. Moderne IDEs können Typed Properties außerdem für eine präzisere Autovervollständigung und statische Analyse nutzen. Tools wie PHPStan und Psalm profitieren ebenfalls von den expliziten Typdeklarationen und können potenzielle Fehler bereits vor der Ausführung aufdecken. Zusammen mit declare(strict_types=1) und Constructor Promotion bilden Typed Properties das Fundament für modernes, typsicheres PHP.
Fazit
Typed Properties sind eine grundlegende Ergänzung für typsicheren PHP Code. Sie wurden mit PHP 7.4 eingeführt und ermöglichen die Deklaration von Datentypen direkt an Klasseneigenschaften. Der spezielle Zustand „uninitialized“ unterscheidet sich bewusst von null und erzwingt eine explizite Initialisierung. Nullable Properties mit dem Fragezeichen Operator erlauben null als gültigen Wert, benötigen aber dennoch einen expliziten Standardwert. Statische Properties, Vererbungsregeln und die Kombination mit declare(strict_types=1) runden das Typensystem ab. Ab PHP 8.0 vereinfacht Constructor Promotion die Deklaration zusätzlich, und ab PHP 8.1 sorgt readonly für Unveränderlichkeit. Typed Properties machen PHP Code lesbarer, wartbarer und robuster gegen Laufzeitfehler.