---
title: 'PHP 7.4 from 7.3: Typed Properties, Arrow Functions, FFI & Migration | DevSense'
description: 'Upgrade-Leitfaden für PHP 7.4: Typisierte Eigenschaften, Arrow Functions (Pfeilfunktionen), Varianz, ??=, Spread-Operator in Arrays, WeakReference, __serialize/__unserialize, OPcache-Preloading, FFI – und BC-Breaks für reale Anwendungen.'
faq:
    - { question: 'Was sind typisierte Eigenschaften in PHP 7.4?', answer: 'PHP 7.4 erlaubt Typdeklarationen für Klasseneigenschaften. Der Zugriff auf eine nicht initialisierte typisierte Eigenschaft vor der Wertzuweisung wirft einen TypeError.' }
    - { question: 'Wie funktionieren Arrow Functions in PHP 7.4?', answer: "Arrow Functions (Pfeilfunktionen) verwenden das Schlüsselwort 'fn' und erfassen Variablen aus dem Elternbereich automatisch per Wertkopie (by value). Sie sind auf einen einzelnen Ausdruck beschränkt, der implizit zurückgegeben wird." }
    - { question: 'Was ist OPcache-Preloading?', answer: 'Preloading ermöglicht das Laden von PHP-Dateien in den Speicher beim Systemstart. Dadurch stehen sie allen Requests dauerhaft ohne Parsing-Overhead zur Verfügung. Für Aktualisierungen ist jedoch ein Server-Neustart erforderlich.' }
    - { question: 'Was ist der neue Mechanismus für benutzerdefinierte Serialisierung in PHP 7.4?', answer: "PHP 7.4 führt die magischen Methoden '__serialize' und '__unserialize' ein. Diese ersetzen das alte 'Serializable'-Interface und bieten einen robusteren Weg, um die Serialisierung anzupassen." }
published: '2026-05-31'
---
# PHP 7.4: Hauptmerkmale

Stellen Sie sich vor, Sie aktualisieren Ihre PHP-Version, und Ihre Anwendung stürzt im Live-Betrieb ab, weil eine Klasseneigenschaft nicht initialisiert wurde. PHP 7.4 bringt die lang ersehnte Typsicherheit für Klasseneigenschaften, fordert dafür jedoch die strikte Einhaltung, dass diese vor dem ersten Zugriff initialisiert sein müssen. Es dient als ultimative Brücke zum modernen PHP 8 und führt typisierte Eigenschaften sowie Arrow Functions ein, die Entwicklern Disziplin abverlangen.

## Inhalt
* [Typisierte Eigenschaften](#typed-properties)
* [Arrow Functions (Pfeilfunktionen)](#arrow-functions)
* [Kovarianz & Kontravarianz](#variance)
* [Null-Coalescing-Zuweisung (`??=`)](#null-coalesce-assign)
* [Spread-Operator in Arrays](#array-spread)
* [Trennzeichen in numerischen Literalen](#numeric-separator)
* [Weak References (Schwache Referenzen)](#weak-references)
* [`__toString()` darf Exceptions werfen](#tostring-exceptions)
* [Serialisierung: `__serialize` / `__unserialize`](#custom-serialize)
* [Bemerkenswerte Erweiterungen & Stdlib](#extensions-stdlib)
* [Praktische Rezepte](#practical-recipes)
* [Häufige Fehler](#common-mistakes)
* [Einschränkungen](#limitations)
* [Rückwärtskompatibilität und BC-Breaks (Migrationshinweise)](#backward-incompatible)
* [Veraltete Features (frühzeitig beheben)](#deprecations)
* [Weitere Änderungen & Betrieb (Build, INI, Performance)](#other-changes)
* [Interaktives Quiz](#interactive-quiz)
* [Schlussgedanken](#closing-thoughts)

---

<a id="typed-properties"></a>
## Typisierte Eigenschaften

Klasseneigenschaften können Typen deklarieren. Nicht initialisierte typisierte Eigenschaften **dürfen vor der Zuweisung nicht ausgelesen werden** – andernfalls erhalten Sie den Fehler **`Typed property ... must not be accessed before initialization`**.

```php
// src/User.php
final class User
{
    public int $id;
    public string $name;
    public ?string $nickname = null;
}
```

Hinweise aus der Praxis:

* Verwenden Sie **`?Typ`** oder einen Standardwert, wenn ein ungesetzter Zustand valide ist.
* **`callable`** ist als Eigenschaftstyp **nicht** erlaubt (kontextabhängig).
* Sie können bei der Deklaration keinen Standardwert wie `new SomeClass()` für Objekte angeben, wie es bei Skalaren möglich ist; Objekteigenschaften sind hier eingeschränkt.

> [!NOTE]
> Wussten Sie schon? In PHP 7.4 sind typisierte Eigenschaften auf Engine-Ebene mit einer Absicherung für die verzögerte Initialisierung ("lazy initialization") implementiert. Eine Eigenschaft existiert in einem "uninitialisierten" Zustand, der sich von `null` unterscheidet. Eine Prüfung mit `isset($user->id)` liefert `false`, wenn noch kein Wert zugewiesen wurde – selbst wenn der Typ nicht-nullable ist.

---

<a id="arrow-functions"></a>
## Arrow Functions (Pfeilfunktionen)

Arrow Functions (`fn`) erfassen Variablen aus dem umgebenden Bereich **per Wertkopie (by value)** und geben einen einzelnen Ausdruck zurück – ideal für kurze Callbacks.

```php
// src/MathHelper.php
$factor = 10;
$nums = array_map(fn($n) => $n * $factor, [1, 2, 3]);
```

**`fn` ist ein reserviertes Wort**: Sie können keine Funktionen oder Klassen mehr `fn` nennen (Methoden- und Konstantennamen sind jedoch weiterhin erlaubt).

> [!NOTE]
> Wussten Sie schon? Im Gegensatz zu Arrow Functions in JavaScript erfassen PHP-Pfeilfunktionen Variablen ausschließlich per Wertkopie (by-value). Sie können eine Variable im äußeren Bereich nicht von innerhalb der Arrow Function heraus modifizieren.

---

<a id="variance"></a>
## Kovarianz & Kontravarianz

Rückgabetypen können bei der Vererbung **kovariant** sein und Parametertypen **kontravariant** (mit gewissen Einschränkungen). Volle Varianz funktioniert am besten mit **Autoloading**; in einer einzelnen Datei sind aufgrund der Ladereihenfolge der Klassen nur **zyklenfreie** Referenzen möglich.

```php
// src/Repository.php
interface Repository {
    public function get(int $id): object;
}

class UserRepository implements Repository {
    public function get(int $id): User { // Kovarianter Rückgabetyp
        return new User();
    }
}
```

---

<a id="null-coalesce-assign"></a>
## Null-Coalescing-Zuweisung (`??=`)

Weist einen Wert nur dann zu, wenn die linke Seite ungesetzt oder null ist:

```php
// src/Config.php
$config['debug'] ??= false;
```

---

<a id="array-spread"></a>
## Spread-Operator in Arrays

Entpacken Sie Iterables innerhalb von Array-Literalen:

```php
// src/ArrayMerge.php
$base = [1, 2];
$all = [0, ...$base, 3]; // [0, 1, 2, 3]
```

Lässt sich gut mit `array_merge(...$arrays)` kombinieren, da `array_merge()` nun auch **ohne Argumente** aufgerufen werden kann (gibt dann `[]` zurück).

---

<a id="numeric-separator"></a>
## Trennzeichen in numerischen Literalen

Unterstriche verbessern die Lesbarkeit und verändern den Wert nicht:

```php
// src/Constants.php
$million = 1_000_000;
$hex = 0xFF_FF_FF;
```

---

<a id="weak-references"></a>
## Weak References (Schwache Referenzen)

`WeakReference` ermöglicht es Ihnen, eine Referenz zu halten, die das referenzierte Objekt **nicht** vor der Garbage Collection schützt – nützlich für Caches und Graphen, um Memory Leaks zu vermeiden.

```php
// src/Cache.php
$obj = new stdClass();
$weakRef = WeakReference::create($obj);
```

---

<a id="tostring-exceptions"></a>
## `__toString()` darf Exceptions werfen

Das Werfen von Exceptions aus `__toString()` heraus ist nun erlaubt (zuvor führte dies zu einem Fatal Error). Einige frühere behebbare Fehler wurden zu **`Error`**-Exceptions – prüfen Sie Code-Pfade mit String-Casts.

```php
// src/Stringy.php
class Stringy {
    public function __toString(): string {
        throw new Exception("String-Cast fehlgeschlagen");
    }
}
```

---

<a id="custom-serialize"></a>
## Serialisierung: `__serialize` / `__unserialize`

Neue Hooks ersetzen Ad-hoc-Muster und lösen das `Serializable`-Interface langfristig ab:

```php
// src/Point.php
final class Point
{
    private int $x;
    private int $y;

    public function __serialize(): array
    {
        return ['x' => $this->x, 'y' => $this->y];
    }

    public function __unserialize(array $data): void
    {
        $this->x = $data['x'];
        $this->y = $data['y'];
    }
}
```

SPL-Typen wie `ArrayObject` können **neue** Payloads erzeugen, die ab PHP 7.4 lesbar sind, nicht jedoch von älteren PHP-Versionen.

---

<a id="extensions-stdlib"></a>
## Bemerkenswerte Erweiterungen & Stdlib

* **FFI**: Rufen Sie C-Bibliotheken direkt aus PHP auf (sehr mächtig; Sandboxing und Sicherheitsüberprüfung zwingend erforderlich).
* **OPcache-Preloading**: Laden Sie eine Auswahl an Dateien einmalig beim Systemstart, um Autoloading-Kosten zu minimieren – erfordert `opcache.preload` und meist `opcache.preload_user`.
* **`mb_str_split()`**: Verhält sich wie `str_split()`, arbeitet jedoch auf **Unicode Code Points**.
* **`proc_open()`**: Befehle können als **Array** übergeben werden (kein Shell-Wrapping nötig), unterstützt zudem `redirect` / `null` Deskriptoren.
* **`strip_tags()`**: Erlaubte Tags können als **Array** von Namen übergeben werden.
* **PDO**: Benutzername/Passwort können nun im DSN für mehr Treiber angegeben werden; **`??`** in SQL maskiert ein literales `?` (z. B. PostgreSQL JSON-Operatoren `?`).
* **PCRE**: `preg_replace_callback*` akzeptiert `flags` (`PREG_OFFSET_CAPTURE`, `PREG_UNMATCHED_AS_NULL`).
* **Password**: Argon2 über **sodium**, wenn ohne libargon kompiliert wurde.

---

<a id="practical-recipes"></a>
## Praktische Rezepte

### Sichere Standardwerte mit `??=`

```php
// src/recipes.php
$options['timeout'] ??= 30;
```

### Arrow Function in einer Sortierung

```php
// src/recipes.php
usort($rows, fn($a, $b) => $a['score'] <=> $b['score']);
```

### Spread-Merge dynamischer Listen

```php
// src/recipes.php
$merged = array_merge(...$chunks);
```

---

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

Hier sind typische Stolpersteine für Entwickler beim Übergang zu PHP 7.4:

### 1. Auslesen nicht initialisierter typisierter Eigenschaften
```php
// src/BadPropertyAccess.php
// Schlecht: Das Auslesen der Eigenschaft vor der Wertzuweisung wirft einen Fatal Error
class BadUser {
    public int $id;
}
$user = new BadUser();
echo $user->id; // Fatal Error: Typed property BadUser::$id must not be accessed before initialization
```
```php
// src/GoodPropertyAccess.php
// Gut: Bieten Sie einen Standardwert an oder initialisieren Sie im Konstruktor
class GoodUser {
    public int $id = 0; // Standardwert
    // ODER:
    // public function __construct(int $id) { $this->id = $id; }
}
```

### 2. Modifizieren von Variablen des äußeren Bereichs in Arrow Functions
```php
// src/BadArrowScope.php
// Schlecht: Annahme, dass Arrow Functions Variablen des äußeren Bereichs per Referenz erfassen
$count = 0;
$increment = fn() => $count++;
$increment();
echo $count; // Ausgabe: 0 (Die äußere Variable bleibt unverändert!)
```
```php
// src/GoodArrowScope.php
// Gut: Verwenden Sie traditionelle anonyme Funktionen mit expliziter Referenzbindung
$count = 0;
$increment = function() use (&$count) {
    $count++;
};
$increment();
echo $count; // Ausgabe: 1
```

---

<a id="limitations"></a>
## Einschränkungen

* **Arrow Functions**: Sind strikt auf einen einzelnen Ausdruck beschränkt. Sie können keine mehrzeilige Logik oder Return-Anweisungen enthalten.
* **OPcache-Preloading**: Vorgeladene Dateien verbleiben dauerhaft im Speicher. Jede Änderung am Code erfordert einen vollständigen Neustart von PHP-FPM oder des Webservers.
* **FFI**: Bietet enorme Performance, umgeht jedoch die Sicherheitsmechanismen von PHP. Es ist anfällig für Speicherfehler (Segmentation Faults) und sollte nicht in nicht vertrauenswürdigen Shared-Hosting-Umgebungen eingesetzt werden.

---

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

### Core

* **Array-Zugriff auf Nicht-Arrays**: Die Verwendung von `null`, `bool`, `int`, `float` oder `resource` wie `$x['k']` erzeugt eine **Notice**.
* **`get_declared_classes()`**: Listet **anonyme** Klassen erst auf, nachdem sie instantiiert wurden.
* **`fn`**: Reserviertes Schlüsselwort für Klassen- oder Funktionsnamen.
* **`<?php` am Dateiende** ohne Zeilenumbruch: Wird nun als **geöffnetes Tag** interpretiert (zuvor war dies uneindeutig bei `short_open_tag`).
* **Stream-Wrapper**: `include`/`require` auf Streams ruft eventuell `stream_set_option(STREAM_OPTION_READ_BUFFER)` auf – implementieren Sie dies oder geben Sie `false` zurück, um Warnungen zu vermeiden.
* **Serialisierung**: **`o` Format entfernt** (betraf nur speziell präparierte Payloads).
* **Passwort-Konstanten**: `PASSWORD_*` Bezeichner sind nun **Strings** (`'2y'`, `'argon2id'`, …) statt Integer – Vergleiche mit `1`/`2`/`3` schlagen fehl.
* **`htmlentities()`**: Erzeugt eine **Notice**, wenn die Kodierung auf das Verhalten von `htmlspecialchars` zurückfällt.
* **`fread`/`fwrite`**: Geben im Fehlerfall **`false`** zurück (nicht `''` oder `0`); Fehler können eine **Notice** erzeugen.
* **BCMath**: Warnt bei ungültigen numerischen Strings (werden weiterhin als Null gewertet).
* **CURL**: Serialisieren von **`CURLFile`** wirft früher Fehler; `curl_version($nonDefault)` warnt bei Werten ungleich `CURLVERSION_NOW`.
* **Date**: Das Dumpen von `DateTime*` hinterlässt keine verwaisten Eigenschaften mehr; **`DateInterval`-Vergleiche** erzeugen eine Warnung und liefern immer `false`.
* **Intl**: Der Standard-Variantentyp für `idn_to_ascii` / `idn_to_utf8` ist nun **`INTL_IDNA_VARIANT_UTS46`**.
* **MySQLi**: Eingebetteter Server wurde entfernt; undokumentierte Eigenschaft `$mysqli->stat` wurde entfernt – nutzen Sie **`mysqli::stat()`**.
* **OpenSSL**: `openssl_random_pseudo_bytes` wirft bei Fehlern Exceptions wie **`random_bytes`**; `$crypto_strong` ist bei erfolgreichem Durchlauf `true`.
* **PCRE**: Mit **`PREG_UNMATCHED_AS_NULL`** werden nicht übereinstimmende Gruppen am Ende als **`null`** gewertet (stabilisiert die `$matches` Array-Größe).
* **PDO**: Serialisieren von **`PDO`/`PDOStatement`** wirft eine **`Exception`** (keine `PDOException`).
* **Reflection**: Serialisieren von Reflection-Objekten **wirft Fehler**; einige **Zahlenwerte von Modifikator-Konstanten** wurden geändert.
* **SPL / `ArrayObject`**: Verhalten von **`get_object_vars`** wurde geändert, es sei denn, `STD_PROP_LIST` ist gesetzt; `SplPriorityQueue::setExtractFlags(0)` wirft sofort Fehler.
* **Tokenizer**: Unerwartete Bytes erzeugen **`T_BAD_CHARACTER`** statt Lücken im Token-Stream.
* **Cookies (ab 7.4.11)**: Cookie-**Namen** werden nicht mehr URL-dekodiert.

---

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

Wichtige Punkte:

* **Verschachtelte Ternäre Operatoren** ohne explizite Klammerung (außer der eindeutigen Form mit mittlerem Operanden).
* **Array-Zugriffe mit geschweiften Klammern** `$str{0}` / `$arr{0}` → stattdessen `[]` nutzen.
* **`(real)`** / **`is_real()`** → **`(float)`** / **`is_float()`**.
* **`array_key_exists()` auf Objekte** → **`isset()`** / **`property_exists()`**.
* **`implode($parts, $glue)`** in umgekehrter Reihenfolge → **`implode($glue, $parts)`**.
* **`ReflectionType::__toString()`** und **`Reflection*::export()`** → nutzen Sie stattdessen APIs wie **`ReflectionNamedType::getName()`** und String-Casting von Reflection-Objekten.
* **`allow_url_include`**, **`FILTER_SANITIZE_MAGIC_QUOTES`**, veraltete LDAP-Hilfsfunktionen und viele kleinere Funktionen (`money_format()`, `hebrevc()`, …) – siehe [migration74 deprecated](https://www.php.net/manual/en/migration74.deprecated.php).

---

<a id="interactive-quiz"></a>
## Interaktives Quiz

Testen Sie Ihr Wissen über die Features von PHP 7.4:

1. **Was passiert, wenn Sie eine uninitialisierte typisierte Eigenschaft in PHP 7.4 auslesen?**
   * A) Es gibt `null` zurück.
   * B) Es erzeugt eine Notice und gibt `null` zurück.
   * C) Es wirft eine Error-Exception.
   * D) Es gibt `false` zurück.

   <details>
   <summary>Klicken, um die Antwort anzuzeigen</summary>
   
   **Richtige Antwort: C**  
   PHP 7.4 verbietet das Auslesen einer typisierten Eigenschaft vor deren Initialisierung. Der Versuch wirft einen `Error` (spezifisch `Error: Typed property ... must not be accessed before initialization`).
   </details>

2. **Können Sie eine Variable des äußeren Bereichs aus einer Arrow Function heraus modifizieren?**
   * A) Ja, Variablen werden per Referenz erfasst.
   * B) Nein, Variablen werden per Wertkopie erfasst.
   * C) Ja, aber nur bei Verwendung des `use`-Schlüsselworts.
   * D) Ja, aber nur für Objekte.

   <details>
   <summary>Klicken, um die Antwort anzuzeigen</summary>
   
   **Richtige Antwort: B**  
   Arrow Functions in PHP erfassen Variablen des äußeren Bereichs automatisch per Wertkopie. Änderungen an Variablen innerhalb der Arrow Function sind lokal und betreffen den äußeren Bereich nicht.
   </details>

3. **Welcher Eigenschaftstyp ist in PHP 7.4 NICHT erlaubt?**
   * A) `object`
   * B) `callable`
   * C) `iterable`
   * D) `?string`

   <details>
   <summary>Klicken, um die Antwort anzuzeigen</summary>
   
   **Richtige Antwort: B**  
   Der Typ `callable` ist als Eigenschaftstyp explizit nicht zugelassen, da sein Verhalten stark vom aufrufenden Kontext abhängt.
   </details>

---

<a id="closing-thoughts"></a>
## Schlussgedanken

Betrachten Sie PHP 7.4 als **Übergangsversion**: Führen Sie typisierte Eigenschaften und moderne Serialisierung ein, **bevor** Sie zu den strengeren Fehlermeldungen von 8.0 wechseln. Suchen Sie parallel nach **Integer-basierten Passwort-Algorithmen**, **`fn` Bezeichnern**, der Syntax **`$var{idx}`** und Mustern rund um **ArrayObject** – und prüfen Sie **Streams**, **OpenSSL random** und **PDO/Reflection-Serialisierung** in Ihren Tests.