---
title: 'PHP 8.1: Enums, Fibers, Readonly & Intersection Types — PHP Upgrade Guide | DevSense'
description: 'PHP 8.1 nach 8.0: Enums, Readonly-Eigenschaften, Fibers, Intersection/never Typen, First-Class-Callables – plus $GLOBALS-Regeln, MySQLi-Exceptions und Deprecation-Watchlist.'
faq:
    - { question: 'Was sind Enums in PHP 8.1 und wie werden sie verwendet?', answer: 'Enums sind ein typsicherer Weg, um eine geschlossene Menge möglicher Werte zu definieren. Backed Enums ordnen Fälle String- oder Int-Werten für die Serialisierung zu, während Pure Enums nur auf Identität basieren und abstrakte Zustände darstellen.' }
    - { question: 'Welche Regeln gelten für Readonly-Eigenschaften in PHP 8.1?', answer: 'Readonly-Eigenschaften müssen typisiert sein, dürfen keine Standardwerte haben und können nur einmal initialisiert werden (normalerweise im Konstruktor). Nachfolgende Änderungsversuche werfen einen Fatal Error.' }
    - { question: 'Wie funktioniert die First-Class-Callable-Syntax in PHP 8.1?', answer: 'Sie ermöglicht das Erstellen einer Closure aus jeder aufrufbaren Funktion oder Methode unter Verwendung von drei Punkten `...` (z. B. `strlen(...)`), was die ältere und umständlichere Syntax `Closure::fromCallable()` ersetzt.' }
    - { question: "Wofür wird der Rückgabetyp 'never' verwendet?", answer: 'Der Typ `never` signalisiert, dass eine Funktion niemals einen Wert zurückgibt. Das bedeutet, sie muss entweder `exit()` aufrufen, eine Exception werfen oder in eine Endlosschleife eintreten, was eine bessere statische Analyse ermöglicht.' }
published: '2026-05-31'
---
# PHP 8.1: Hauptmerkmale

Upgrade-Pfad von PHP 8.0.x: Spracherweiterungen, Verschärfungen zur Laufzeit und Migrations-Checklisten für Staging.

## Inhalt
* [Enums (Aufzählungen)](#enums)
* [Readonly-Eigenschaften](#readonly-properties)
* [First-Class-Callable-Syntax](#first-class-callable)
* [Fibers](#fibers)
* [Intersection Types (Schnittmengentypen)](#intersection-types)
* [Rückgabetyp 'never'](#never-type)
* [new in Initialisierern](#new-in-initializers)
* [Syntax- & Sprachoptimierungen (0o, Array-Unpacking, Named Args nach Unpacking)](#syntax-tweaks)
* [Rückwärtskompatibilität und BC-Breaks (Migrationshinweise)](#backward-incompatible)
* [Veraltete Features (frühzeitig beheben)](#deprecations)
* [Erweiterungen: Bemerkenswerte Änderungen](#extensions-changes)
* [Häufige Fehler](#common-mistakes)
* [Selbsttest-Quiz](#self-test-quiz)

---

Während PHP 8.0 ein grundlegender Reset der Laufzeit-Engine war, geht es in PHP 8.1 vor allem um den Feinschliff der Sprachsemantik und die Bereitstellung moderner Syntaxkonstrukte. Durch die Einführung nativer Enums, schreibgeschützter (readonly) Eigenschaften und Schnittmengentypen (intersection types) direkt in das Typsystem ermöglicht PHP 8.1 Entwicklern, deklarativen und typsicheren Code mit weit weniger Boilerplate-Code zu schreiben. Gleichzeitig verschärft diese Version jedoch Annahmen zur Laufzeit – sie schränkt Schreibzugriffe auf `$GLOBALS` ein, erzwingt bei MySQLi standardmäßig Exceptions und markiert Dutzende von Legacy-Verhaltensweisen als veraltet. Hier ist ein praxiserprobter Leitfaden, um diese Funktionen zu verstehen und das Upgrade erfolgreich zu meistern.

<a id="enums"></a>
## Enums (Aufzählungen)

Enums bieten eine native und typsichere Möglichkeit, eine geschlossene Menge von Werten darzustellen.

* **Backed Enums** speichern einen skalaren Wert (`string|int`), der leicht serialisiert oder übertragen werden kann.
* **Pure Enums** besitzen keine Skalarwerte und basieren ausschließlich auf Identität – ideal für Zustandsmaschinen im Domain-Modell.

> [!NOTE]
> **Wussten Sie schon?**
> Enums sind intern als Klassen implementiert! Sie können Interfaces implementieren, Methoden definieren, statische Methoden schreiben und Traits verwenden (wobei Traits in Enums keine Eigenschaften enthalten dürfen), genau wie reguläre Klassen.

```php
// app/Enums/Status.php
enum Status: string
{
    case Draft = 'draft';
    case Published = 'published';
    case Archived = 'archived';
}

// app/Services/PostService.php
function canEdit(Status $status): bool
{
    return $status !== Status::Archived;
}

$status = Status::from('draft');  // Status::Draft
$value  = $status->value;         // 'draft'
```

### Empfehlungen für die Praxis

* Verwenden Sie Enums anstelle von lose typisierten Strings (`'draft'|'published'`) in Methodensignaturen und DTOs.
* Bevorzugen Sie Backed Enums für Datenbank-Persistenz und APIs; nutzen Sie Pure Enums für interne Workflow-Zustände.
* Kombinieren Sie Enums mit `match` für eine vollständige Abdeckung aller Fälle:

```php
// app/Services/PostService.php
function label(Status $status): string
{
    return match ($status) {
        Status::Draft => 'Entwurf',
        Status::Published => 'Veröffentlicht',
        Status::Archived => 'Archiviert',
    };
}
```

---

<a id="readonly-properties"></a>
## Readonly-Eigenschaften

Readonly-Eigenschaften können **nur einmal** zugewiesen werden, typischerweise im Konstruktor. Dies ist ein großer Gewinn für unveränderliche DTOs, Value Objects und sicherere Domain-Modelle.

> [!NOTE]
> **Wussten Sie schon?**
> Eine schreibgeschützte Eigenschaft darf keinen Standardwert haben! Wenn Sie versuchen, `public readonly string $status = 'draft';` zu schreiben, löst PHP einen Fatal Error zur Kompilierzeit aus.

```php
// app/DTO/UserProfile.php
final class UserProfile
{
    public function __construct(
        public readonly int $id,
        public readonly string $email,
    ) {}
}
```

### Architektonische Auswirkungen

* Fördert das Konzept von „vollständig konstruieren, danach nicht mehr verändern“-Objekten.
* Reduziert die Notwendigkeit von privaten Eigenschaften und dazugehörigen Gettern bei reinen Datenstrukturen.
* Funktioniert hervorragend mit Constructor Property Promotion für kompakte, unveränderliche Typen.

---

<a id="first-class-callable"></a>
## First-Class-Callable-Syntax

PHP 8.1 führt einen komfortablen Weg ein, um Closures aus Callables zu erstellen:

```php
// app/Helpers/StringHelper.php
function normalize(string $s): string
{
    return strtolower(trim($s));
}

// app/Services/DataService.php
$fn = normalize(...);               // Closure
$out = array_map($fn, [' A ', 'B ']); // ['a', 'b']
```

Dies ist funktional identisch mit `Closure::fromCallable('normalize')`, ist jedoch kürzer und lässt sich in Daten-Pipelines flüssiger lesen.

---

<a id="fibers"></a>
## Fibers

Fibers sind ein Low-Level-Primitiv für **kooperative Nebenläufigkeit**. Sie machen Code nicht automatisch asynchron, ermöglichen es aber Frameworks und Bibliotheken, asynchrone Runtimes, Scheduler und strukturierte Nebenläufigkeit zu implementieren.

```php
// app/Services/FiberService.php
$fiber = new Fiber(function (): void {
    $value = Fiber::suspend('pausiert');
    echo "fortgesetzt mit: {$value}\n";
});

echo $fiber->start() . "\n"; // pausiert
$fiber->resume('payload');   // fortgesetzt mit: payload
```

### Relevanz in der Praxis

* Wenn Sie ein asynchrones Framework (wie ReactPHP oder Amp) verwenden: Fibers vereinfachen die Integration erheblich.
* Für klassische Request/Response-Webanwendungen: Fibers sind in erster Linie Infrastruktur-Komponenten für Bibliotheken.

---

<a id="intersection-types"></a>
## Intersection Types (Schnittmengentypen)

Schnittmengentypen drücken aus, dass ein Wert **alle** angegebenen Interfaces oder Klassen gleichzeitig erfüllen muss.

```php
// app/Services/ExporterService.php
function export(iterable&Countable $items): array
{
    if (count($items) === 0) {
        return [];
    }

    return iterator_to_array($items, preserve_keys: true);
}
```

Hinweis: Schnittmengentypen können in PHP 8.1 nicht mit Union-Typen kombiniert werden (sogenannte DNF-Typen wurden erst in PHP 8.2 eingeführt).

---

<a id="never-type"></a>
## Rückgabetyp 'never'

Der Rückgabetyp `never` signalisiert, dass eine Funktion **niemals zurückkehrt**: Sie wirft entweder immer eine Exception oder beendet die Skriptausführung mit `exit()`.

```php
// app/Helpers/ErrorHelper.php
function fail(string $message): never
{
    throw new RuntimeException($message);
}
```

Dies verbessert die statische Code-Analyse und macht den Kontrollfluss im Code explizit.

---

<a id="new-in-initializers"></a>
## new in Initialisierern

PHP 8.1 erlaubt `new`-Ausdrücke an mehr Orten: als Parameter-Standardwerte, in statischen Variablen, in Konstanten-Initialisierern und als Argumente für Attribute.

```php
// app/Services/Clock.php
final class Clock
{
    public function now(): DateTimeImmutable
    {
        return new DateTimeImmutable('now');
    }
}

// app/Services/HandlerService.php
function handler(Clock $clock = new Clock()): DateTimeImmutable
{
    return $clock->now();
}
```

Dies vermeidet eine Menge Boilerplate-Code für Fabriken in einfachen Szenarien. (Achten Sie jedoch auf Lebenszyklen von Services, wenn Sie einen DI-Container nutzen.)

---

<a id="syntax-tweaks"></a>
## Syntax- & Sprachoptimierungen

### Oktal-Präfix für Ganzzahlen: `0o` / `0O`

```php
// app/Config/FileConfig.php
$mask = 0o755;
```

### Array-Unpacking mit String-Schlüsseln

```php
// app/Services/ArrayService.php
$a = [1, 'a' => 'b'];
$b = [...$a, 'c' => 'd']; // [1, 'a' => 'b', 'c' => 'd']
```

### Benannte Argumente nach dem Entpacken von Argumenten

```php
// app/Services/ArgumentService.php
foo(...$args, named: $arg);
```

### `full_path` bei Datei-Uploads

`$_FILES`-Einträge enthalten nun einen `full_path`-Schlüssel (gedacht für Uploads mittels `webkitdirectory`).

---

<a id="backward-incompatible"></a>
## Rückwärtskompatibilität und BC-Breaks (Migrationshinweise)

Dieser Abschnitt konzentriert sich auf Aspekte, die beim Upgrade häufig zu Fehlern in bestehenden Anwendungen führen.

### PHP-Core / Sprache

* **Schreibbeschränkungen für $GLOBALS**: Das Überschreiben des gesamten `$GLOBALS`-Arrays wird nicht mehr unterstützt (z. B. führt `array_pop($GLOBALS)` zu Fehlern). Der Zugriff auf einzelne Elemente wie `$GLOBALS['x']` funktioniert weiterhin.
* **Statische Variablen in vererbten Methoden**: Vererbte (nicht überschriebene) Methoden teilen sich statische Variablen nun mit der Elternmethode.
* **Optionale vor erforderlichen Parametern**: Optionale Parameter, die vor erforderlichen deklariert wurden, werden als erforderlich behandelt. In PHP 8.1 kann dies nun zum Aufrufzeitpunkt einen `ArgumentCountError` auslösen.
* **Rückgabetyp-Kompatibilität bei internen Klassen**: Das Überschreiben interner Methoden ohne kompatible Rückgabetypen löst Deprecation-Warnungen aus. Nutzen Sie `#[ReturnTypeWillChange]` bei Bedarf.
* **Neue Schlüsselwörter**:
  * `readonly` ist nun ein Schlüsselwort (derzeit noch als Funktionsname erlaubt).
  * `never` ist nun ein reserviertes Wort (darf nicht für Klassen, Interfaces oder Traits verwendet werden).

### Migration von Ressourcen zu Objekten

Mehrere Erweiterungen haben traditionelle Ressourcen in Objekte umgewandelt (passen Sie eventuelle Prüfungen mit `is_resource()` entsprechend an):

* **FileInfo**: Verwendet `finfo`-Objekte statt Ressourcen.
* **FTP**: Verwendet `FTP\Connection`-Objekte.
* **IMAP**: Verwendet `IMAP\Connection`-Objekte.
* **LDAP**: Verwendet `LDAP\Connection`-, `LDAP\Result`- und `LDAP\ResultEntry`-Objekte.
* **PgSQL**: Verwendet `PgSql\Connection`-, `PgSql\Result`- und `PgSql\Lob`-Objekte.
* **PSpell**: Verwendet `PSpell\Dictionary`- und `PSpell\Config`-Objekte.

### PDO / MySQLi Verhaltensänderungen

* **MySQLi**: Der Standard-Fehlermeldungsmodus wurde von „silent“ auf „exceptions“ geändert. Zur Wiederherstellung des alten Verhaltens: `mysqli_report(MYSQLI_REPORT_OFF);`
* **PDO**: Das Verhalten von `PDO::ATTR_STRINGIFY_FETCHES` für Booleans wurde geändert; SQLite- und MySQL-Treiber geben Integers und Floats nun konsistenter als native PHP-Typen zurück.

### Standard-Bibliothek

* `version_compare()` akzeptiert keine undokumentierten Abkürzungen für Operatoren mehr.
* HTML-Escaping-Funktionen verwenden nun standardmäßig `ENT_QUOTES | ENT_SUBSTITUTE` (Anführungszeichen werden maskiert; ungültiges UTF-8 wird ersetzt).

---

<a id="deprecations"></a>
## Veraltete Features (frühzeitig beheben)

Deprecations in 8.1 sind die Fehler von morgen. Sie frühzeitig zu beheben, zahlt sich beim späteren Upgrade auf PHP 8.2+ aus.

### Core-Deprecations

* Die Übergabe von `null` an nicht-nullable Parameter integrierter Funktionen ist veraltet.
* Implizite verlustbehaftete Float-zu-Int-Konvertierungen sind veraltet (z. B. bei Array-Schlüsseln oder Typdeklarationen).
* Der Aufruf statischer Elemente auf einem Trait ist veraltet.
* Autovivifikation aus `false` ist veraltet (`$x = false; $x[] = 1;`).

### Wichtige Erweiterungs-Deprecations

* **Date**: `strftime()` / `gmstrftime()` und `strptime()` sind veraltet (nutzen Sie stattdessen `date()` / `IntlDateFormatter`).
* **Filter**: `FILTER_SANITIZE_STRING` und `FILTER_SANITIZE_STRIPPED` sind veraltet.
* **Hash**: `mhash*()`-Funktionen sind veraltet (nutzen Sie `hash_*()`).
* **PDO**: `PDO::FETCH_SERIALIZE` ist veraltet.

---

<a id="common-mistakes"></a>
## ⚠️ Häufige Fehler

Hier sind typische Stolpersteine bei der Nutzung der Features von PHP 8.1:

### 1. Modifizieren von Readonly-Eigenschaften
Eine `readonly`-Eigenschaft kann nach ihrer Initialisierung nicht mehr verändert werden – selbst nicht aus der Klasse selbst heraus oder durch eine Kindklasse.

```php
// app/DTO/UserProfile.php
// SCHLECHT: Das Ändern einer Readonly-Eigenschaft nach der Initialisierung wirft einen Fehler
class UserProfile {
    public function __construct(public readonly string $email) {}

    public function updateEmail(string $newEmail): void {
        $this->email = $newEmail; // Fatal Error: Cannot modify readonly property
    }
}
```

### 2. Autovivifikation aus False
In PHP 8.1 ist das automatische Erstellen eines Arrays aus einer Variablen, die auf `false` gesetzt ist, veraltet.

```php
// app/Services/ArrayService.php
// SCHLECHT: Löst in PHP 8.1 eine Deprecation-Warnung aus (und in PHP 8.2 einen Fatal Error)
$data = false;
$data[] = 'value';

// GUT: Initialisieren Sie zuerst ein leeres Array
$data = [];
$data[] = 'value';
```

### 3. Neuzuweisung des $GLOBALS-Arrays
Sie können Variablen innerhalb von `$GLOBALS` modifizieren, aber Sie können das `$GLOBALS`-Array nicht als Ganzes neu zuweisen oder zerstören.

```php
// app/Services/LegacyService.php
// SCHLECHT: Fatal Error in PHP 8.1
$GLOBALS = []; 

// SCHLECHT: Referenzbindung ist nicht erlaubt
$GLOBALS = &$someOtherArray;
```

---

<a id="self-test-quiz"></a>
## Selbsttest-Quiz

Testen Sie Ihr Wissen über PHP 8.1.

### Frage 1: Welche Aussage zu Readonly-Eigenschaften in PHP 8.1 ist korrekt?
* A) Sie können neu zugewiesen werden, solange der neue Wert denselben Typ hat.
* B) Sie können nur auf typisierten Eigenschaften deklariert werden (nicht auf untypisierten).
* C) Ihnen kann in der Klassendeklaration ein Standardwert zugewiesen werden.

<details>
<summary>Antworten anzeigen</summary>

**Richtige Antwort: B**  
In PHP 8.1 kann `readonly` nur auf typisierte Eigenschaften angewendet werden. Die Deklaration ohne Typ führt zu einem Syntaxfehler. Zudem dürfen sie keine Standardwerte besitzen und nach der Initialisierung niemals neu zugewiesen werden.
</details>

### Frage 2: Was passiert in PHP 8.1, wenn Sie versuchen, aus einer Variable, die `false` enthält, automatisch ein Array aufzubauen (`$x = false; $x[] = 1;`)?
* A) Es funktioniert problemlos und wandelt die Variable in ein Array um.
* B) Es wird eine Deprecation-Warnung ausgelöst.
* C) Es wird sofort ein Fatal Error geworfen.

<details>
<summary>Antworten anzeigen</summary>

**Richtige Antwort: B**  
In PHP 8.1 ist die Autovivifikation aus `false` veraltet und erzeugt eine Warnung. In PHP 8.2 wird dies zu einem Fatal Error hochgestuft.
</details>

---

## Zusammenfassung

Während PHP 8.0 ein technischer Reset war, verfeinert PHP 8.1 die Semantik und führt moderne Konstrukte ein. Durch Enums, Readonly-Eigenschaften und Schnittmengentypen direkt im Typsystem schreiben Sie saubereren, typsichereren Code mit deutlich weniger Boilerplate.