PHP 8.4 wurde im November 2024 veröffentlicht und bringt einige der interessantesten Sprachfeatures seit Jahren. Property Hooks und Asymmetric Visibility verändern grundlegend, wie man Objekte mit Eigenschaften modelliert. Dieser Beitrag zeigt die wichtigsten Neuerungen anhand von Praxisbeispielen.
Property Hooks
Property Hooks sind das Highlight von PHP 8.4. Sie erlauben es, beim Lesen (get) und Schreiben (set) einer Property eigene Logik auszuführen — ohne explizite Getter- und Setter-Methoden.
Grundlegende Syntax
<?php
declare(strict_types=1);
class Temperature
{
public float $celsius {
get => $this->celsius;
set (float $value) {
if ($value < -273.15) {
throw new \ValueError('Temperature below absolute zero');
}
$this->celsius = $value;
}
}
public function __construct(float $celsius)
{
$this->celsius = $celsius;
}
}
$temp = new Temperature(20.0);
echo $temp->celsius; // 20.0
$temp->celsius = -300; // ValueError: Temperature below absolute zero
Berechnete Properties
Ein häufiger Anwendungsfall: Properties, die aus anderen Properties berechnet werden:
<?php
declare(strict_types=1);
class FullName
{
public string $full {
get => trim($this->first . ' ' . $this->last);
}
public function __construct(
public string $first,
public string $last,
) {
}
}
$name = new FullName('Thomas', 'Wunner');
echo $name->full; // "Thomas Wunner"
Property Hooks in Interfaces
Interfaces können Property Hooks definieren, die implementierende Klassen erfüllen müssen:
<?php
declare(strict_types=1);
interface HasLabel
{
public string $label { get; }
}
class Product implements HasLabel
{
public string $label {
get => strtoupper($this->name);
}
public function __construct(
public readonly string $name,
) {
}
}
Asymmetric Visibility
Asymmetric Visibility löst ein jahrelanges Problem: Properties, die von außen lesbar, aber nicht oder nur eingeschränkt schreibbar sein sollen. Bisher war das nur über explizite Getter möglich.
<?php
declare(strict_types=1);
class Order
{
// Öffentlich lesbar, nur intern schreibbar
public private(set) string $status = 'pending';
// Öffentlich lesbar, von Subklassen und intern schreibbar
public protected(set) \DateTimeImmutable $createdAt;
public function __construct()
{
$this->createdAt = new \DateTimeImmutable();
}
public function confirm(): void
{
$this->status = 'confirmed'; // Intern: erlaubt
}
}
$order = new Order();
echo $order->status; // "pending" — lesen ok
$order->status = 'confirmed'; // Error: Cannot modify public(private set) property
$order->confirm(); // Über Methode: ok
Im Vergleich zu readonly
readonly erlaubt nur eine einmalige Zuweisung. private(set) erlaubt beliebig viele Zuweisungen, aber nur intern:
<?php
declare(strict_types=1);
class Counter
{
public private(set) int $count = 0;
public function increment(): void
{
$this->count++; // Erlaubt, weil intern
}
}
$counter = new Counter();
$counter->increment();
$counter->increment();
echo $counter->count; // 2 — lesen ok
$counter->count = 5; // Error — von außen nicht schreibbar
Neue Array-Funktionen
PHP 8.4 fügt vier neue Array-Funktionen hinzu, die häufige Operationen vereinfachen.
array_find()
Gibt das erste Element zurück, das den Callback erfüllt — analog zu JavaScript's Array.find():
<?php
declare(strict_types=1);
$users = [
['name' => 'Alice', 'age' => 30],
['name' => 'Bob', 'age' => 25],
['name' => 'Charlie', 'age' => 35],
];
$adult = array_find($users, fn(array $u): bool => $u['age'] >= 30);
// ['name' => 'Alice', 'age' => 30]
// Bisher musste man schreiben:
$adult = null;
foreach ($users as $user) {
if ($user['age'] >= 30) {
$adult = $user;
break;
}
}
array_find_key()
Gibt den Schlüssel des ersten passenden Elements zurück:
<?php
declare(strict_types=1);
$products = ['apple' => 1.20, 'banana' => 0.50, 'cherry' => 2.00];
$expensiveKey = array_find_key($products, fn(float $price): bool => $price > 1.50);
// 'cherry'
array_any() und array_all()
Prüfen ob mindestens ein Element (any) oder alle Elemente (all) eine Bedingung erfüllen:
<?php
declare(strict_types=1);
$scores = [75, 82, 91, 68, 88];
$anyPassed = array_any($scores, fn(int $score): bool => $score >= 90);
// true (91 >= 90)
$allPassed = array_all($scores, fn(int $score): bool => $score >= 60);
// true (alle >= 60)
$allExcellent = array_all($scores, fn(int $score): bool => $score >= 90);
// false
#[\Deprecated] Attribut
PHP 8.4 führt ein offizielles #[\Deprecated]-Attribut ein, mit dem man eigene Funktionen und Methoden als veraltet markieren kann:
<?php
declare(strict_types=1);
class UserService
{
#[\Deprecated(
message: 'Use findByEmail() instead',
since: '2.0',
)]
public function getUserByEmail(string $email): ?User
{
return $this->findByEmail($email);
}
public function findByEmail(string $email): ?User
{
// ...
}
}
Beim Aufruf einer so markierten Methode erzeugt PHP eine E_USER_DEPRECATED-Warnung — genau wie bei PHP-eigenen Deprecated-Funktionen.
HTML5-Parser in ext-dom
Die DOM-Extension erhält einen neuen, vollständig HTML5-konformen Parser, der moderne HTML-Dokumente korrekt parst:
<?php
declare(strict_types=1);
$dom = Dom\HTMLDocument::createFromString('
<html>
<body>
<article>
<h1>Titel</h1>
<p>Inhalt</p>
</article>
</body>
</html>
');
$article = $dom->querySelector('article');
$heading = $article->querySelector('h1');
echo $heading->textContent; // "Titel"
Das ist besonders nützlich für Web-Scraping und HTML-Transformation, wo der bisherige DOMDocument oft mit modernem HTML kämpfte.
Fazit
PHP 8.4 ist ein solides Release, das vor allem die Objektorientierung mit Property Hooks und Asymmetric Visibility erheblich verbessert. Die neuen Array-Funktionen sind willkommene Ergänzungen, die häufige Patterns abkürzen. Wer Symfony 7 oder ein anderes modernes Framework verwendet, kann PHP 8.4 bedenkenlos einsetzen — die Kompatibilität ist hervorragend.
Als erstes Upgrade lohnt sich die Installation:
# In DDEV .ddev/config.yaml
php_version: "8.4"
ddev restart
ddev exec php --version
Kommentare
Kommentare werden von Remark42 bereitgestellt. Beim Laden werden Daten an unseren Kommentar-Server übertragen.