Die PHP Group hat die Version 8.5 der Open-Source-Skriptsprache veröffentlicht, mit der ein Großteil des Internets betrieben wird, darunter auch Websites, die das WordPress CMS nutzen.

Mit der Veröffentlichung von PHP 8.5 im November hat sich die PHP-Gemeinschaft zum zweiten Mal dazu verpflichtet, jedes Jahr wichtige Updates zu veröffentlichen, gefolgt von zwei Jahren aktivem Support für jede Version.

Obwohl 8.5 brandneu ist, haben wir es in unserem jährlichen PHP-Benchmarking bereits hinter einer Reihe beliebter CMS-Plattformen und Frameworks platziert.

Wenn du planst, deine PHP-Anwendungen auf die Version 8.5 zu migrieren, musst du wissen, was sich in dieser neuesten Version geändert hat. Dazu gehören neue Funktionen, die du zur Verbesserung deines Codes nutzen kannst, und alte Funktionen, die die PHP-Entwickler abschaffen wollen.

Hier sind die unserer Meinung nach wichtigsten Neuerungen der neuen Version:

Neue Funktionen und Verbesserungen in PHP 8.5

Beginnen wir mit den neuen Ergänzungen der PHP-Codebasis. Diese Änderungen beginnen in der Regel als Requests for Comments (RFCs), die schließlich genehmigt und einer zukünftigen PHP-Version zugewiesen werden können.

Die im Folgenden beschriebenen neuen Funktionen sind diejenigen, die die meiste Aufmerksamkeit rund um PHP 8.5 auf sich ziehen.

Funktionsaufrufe mit einem Pipe-Operator verketten

Ein neuer Pipe-Operator (|>) verkettet Funktionsaufrufe auf eine Weise, die JavaScript-Programmierern vage bekannt vorkommen wird. Der Pipe-Operator arbeitet von links nach rechts und übergibt bei jedem Schritt einen einzelnen Wert entlang der Kette.

In früheren PHP-Versionen konnten Programmierer/innen eine ähnliche Aufgabe erfüllen, indem sie Funktionen verschachtelten oder eine Reihe von Funktionsaufrufen mit dem jeweils zurückgegebenen Wert durchliefen.

Hier ist ein einfaches Beispiel, das den neuen Pipe-Operator verwendet:

$text = ' New-in-php-8.4 ';

$result = $text
    |> trim(...)
    |> (fn($str) => str_replace('4', '5', $str))
    |> (fn($str) => str_replace('-', ' ', $str))
    |> strtoupper(...);

var_dump($result);
// string(14) "NEW IN PHP 8.5"

(Beachte, dass wir die Syntax für First-Class-Callables (...) verwenden, die in PHP 8.1 mit den Funktionsaufrufen trim() und strtoupper() eingeführt wurde)

Die obige Piping-Kette könnte in einer einzigen Zeile geschrieben werden, aber die Lesbarkeit soll einer der Vorteile dieses neuen Operators sein.

Die obige Kette ist gleichbedeutend mit der Verschachtelung dieser Operationen (in umgekehrter Reihenfolge) wie folgt:

$text = " New-in-php-8.4 ";

$result = strtoupper(
    str_replace(‘-, ' ',
        str_replace('4', '5', 
            trim($text)
         )
     )
);

Alternativ hätte ein Programmierer die Aufgabe in früheren PHP-Versionen auch so lösen können:

$text = " New-in-php-8.4 ";

$result = trim($text);
$result = str_replace('4', '5', $result);
$result = str_replace(‘-, ' ', $result);
$result = strtoupper($result);

URLs mit der neuen URI-Erweiterung parsen

URLs (für diejenigen, die es genauer wissen, auch URIs genannt) sind für die Navigation im Web unerlässlich, aber die Funktion parse_url(), die seit Version 4 in PHP eingebaut ist, ist dafür bekannt, dass sie Probleme mit fehlerhaften Eingaben hat, die zu Fehlern führen können, wenn versucht wird, Website-Adressen zu manipulieren oder zu validieren.

Um das URL-Parsing zu verbessern, enthält PHP 8.5 die Bibliotheken uriparser und Lexbor zur Unterstützung der URL-Standards RFC 3986 und WHATWG.

Du kannst die uniparser-Bibliothek aufrufen, indem du die Arbeit mit der neuen URI-Erweiterung wie folgt beginnst:

$uri = new UriRfc3986Uri("https://kinsta.com/blog/php-8-5/"); 

echo $uri->getScheme();       // https
echo $uri->getHost();         // kinsta.com
echo $uri->getPath();         // /blog/php-8-5

Alternativ dazu kannst du die Lexbor WHATWG URL-Bibliothek wie folgt auswählen:

$uri = new UriWagWgUrl("https://kinsta.com/blog/php-8-5/"); 

echo $uri->getScheme();       // https
echo $uri->getUnicodeHost();  // kinsta.com
echo $uri->getAsciiHost();    // kinsta.com
echo $uri->getPath();         // /blog/php-8-5

Die obigen Beispiele sind die grundlegendsten. Die beiden Bibliotheken, die durch die URI-Erweiterung in PHP 8.5 repräsentiert werden, haben einige Funktionen gemeinsam und weisen auch erhebliche Unterschiede auf.

Ein wichtiger Unterschied ist, dass die RFC 3986-Bibliothek sowohl „rohe“ als auch „normalisiert-dekodierte“ Darstellungen von URIs unterstützt. Das kann bei der Arbeit mit prozentual kodierten Ein- und Ausgaben nützlich sein. In einem Browser zum Beispiel sind diese beiden URIs identisch:

In früheren PHP-Versionen konntest du mit rawurldecode() und rawurlencode() beginnen (die ebenfalls RFC 3986-konform sind), aber die neue Erweiterung ist sofort bereit, mit allen Komponenten von URIs zu arbeiten, unabhängig davon, ob sie kodiert sind oder nicht.

Hier sind einige Beispiele direkt aus dem RFC, der der neuen Parsing-API zugrunde liegt:

$uri = new UriRfc3986Uri("https://%61pple:p%61ss@ex%61mple.com/foob%61r?%61bc=%61bc");
  
echo $uri->getRawUserInfo();  // %61pple:p%61ss
echo $uri->getUserInfo();     // apple:pass
 
echo $uri->getRawUsername();  // %61pple
echo $uri->getUsername();     // apple
 
echo $uri->getRawPassword();  // p%61ss
echo $uri->getPassword();     // pass
 
echo $uri->getRawHost();      // ex%61mple.com
echo $uri->getHost();         // example.com
 
echo $uri->getRawPath();      // /foob%61r
echo $uri->getPath();         // /foobar
 
echo $uri->getRawQuery();     // %61bc=%61bc
echo $uri->getQuery();        // abc=abc

Wenn du die WHATWG-URL-Bibliothek mit der neuen Erweiterung verwendest, werden alle URIs als „roh“ behandelt, es gibt also keinen separaten Funktionssatz zur Unterstützung alternativer Formatierungen. Die Bibliothek kann jedoch zwischen ASCII- und Unicode-Zeichen konvertieren, die häufig in URIs vorkommen.

Strenge Regeln mit der neuen INI-Direktive max_memory_limit

Es heißt, dass mit großer Macht auch große Verantwortung einhergeht. Wenn zu dieser Macht auch die Entscheidung gehört, wie viel Serverspeicher deine PHP-Anwendung nutzen darf, könntest du für Anwendungsabstürze verantwortlich sein, wenn Prozesse mehr Speicher verbrauchen als verfügbar ist.

Zu einer typischen PHP-Installation gehört eine php.ini Datei mit Konfigurationsinformationen, die eine Direktive zur Begrenzung des Speicherverbrauchs für jeden PHP-Prozess (oder Thread) enthält. Eine übliche INI-Direktive für ein Speicherlimit von 128 MB sieht wie folgt aus:

// php.ini
memory_limit 128M

Auf einigen Hosting-Plattformen können Entwickler von PHP-Anwendungen memory_limit mit der Funktion ini_set() in ihrem Code außer Kraft setzen:

ini_set(‘memory_limit’, ‘256M’);
 
// Start code that requires up to 256 MB of memory

Du kannst der Funktion auch den Wert -1 übergeben, wie bei ini_set('memory_limit', '-1') – um überhaupt keine Begrenzung zu erzwingen.

Das Überschreiben der INI-Direktive für ein Speicherlimit kann für Entwickler/innen, die mit den Speicherkonfigurationen der Server, auf denen ihre Anwendungen laufen, nicht genau vertraut sind, riskant sein. Wenn ein oder mehrere PHP-Threads versuchen, mehr als den gesamten Speicherpool zu verbrauchen, kann dies zu einem Absturz der Anwendung führen, ohne dass eine Warnung ausgegeben wird.

PHP 8.5 fügt eine max_memory_limit INI-Direktive hinzu, die als harte Obergrenze dient, selbst wenn die Entwickler/innen Zugriff auf init_set() haben, um die Speichernutzung in ihrem Code zu optimieren.

Hier sind Beispieleinträge in der php.ini Datei einer PHP 8.5 Installation:

// php.ini
max_memory_limit 256M
memory_limit 128M

Mit einer max_memory_limit von 256 MB passiert folgendes in unserem PHP-Code:

ini_set('memory_limit', '256M');  // This is OK
ini_set('memory_limit', '512M');  // Fail with warning
ini_set('memory_limit', '-1');    // Fail with warning

Der Versuch, ein neues Speicherlimit von 512 MB (oder unbegrenzt) zu setzen, ist nicht erfolgreich. Stattdessen wird PHP das Speicherlimit auf den Wert setzen, der max_memory_limit in der Datei php.ini zugewiesen wurde, und eine Warnung ausgeben. (Je nach den Einstellungen der PHP-Installation für die Fehlermeldung wird die Warnmeldung möglicherweise auf dem Bildschirm angezeigt und protokolliert)

Ein kluger Ansatz für PHP 8.5-Entwickler wäre es, die Funktion ini_get() zu verwenden, um zu sehen, ob die neue Höchstgrenze definiert wurde, wie ini_get('max_memory_limit') – und dann entsprechend dem zurückgegebenen Wert anzupassen. Bei PHP-Versionen vor 8.5 würde dieser Aufruf sicher false zurückgeben.

Den ersten oder letzten Wert in einem Array abgreifen

Hebe deine Hand, wenn du angenommen hast, dass PHP bereits über Funktionen verfügt, um die Werte zu lesen, die als erstes oder letztes Mitglied eines Arrays gespeichert sind.

Das war aber nicht der Fall. Aber seit PHP 7.3 gibt es Funktionen, um den ersten und letzten Schlüssel in einem Array zu ermitteln. Um den ersten und letzten Wert zu finden, kannst du also die Funktionen array_key_first() oder array_key_last() verwenden und dann die zurückgegebenen Schlüssel benutzen, um auf die gesuchten Werte zu verweisen:

$array = ["One", "Two", "Three"];

echo $array[array_key_first($array)]; // "One"

Mit PHP 8.5 entfällt ein Schritt für diese Aufgabe und du kannst die Werte direkt mit den neuen Funktionen array_first() und array_last() erreichen.

Es ist alles ganz einfach:

$array = ["One", "Two", "Three"];

echo array_first($array);  // "One"
echo array_last($array);   // "Three"
echo array_last([]);       // null

Oben siehst du, dass ein leeres Array null zurückgibt, aber das allein bestätigt noch nicht, dass das gesamte Array leer ist, denn ein Array-Wert kann auch null sein:

echo array_last([1, 2, null]); // null

Erinnere dich daran, den Rückgabewert einer Funktion zu verwenden

PHP 5.8 fügt ein neues Attribut #[NoDiscard] hinzu, das anzeigt, dass der Rückgabewert einer Funktion kritisch sein könnte. PHP überprüft, ob der Rückgabewert auf irgendeine Weise verbraucht wird, und löst andernfalls eine Warnung aus.

Ein einfaches Beispiel:

#[NoDiscard("this message property will be appended to the built-in warning.")]
function foo(): string {
    return 'bar';
}

// Warning:
// The return value of function foo() is expected to be consumed,
// this message property will be appended to the built-in warning.
foo();

// This will not trigger a warning:
$result = foo();

// Also satisfactory is the (void) cast:
(void) foo();

Im obigen Beispiel wird der Rückgabewert der definierten Funktion zunächst überhaupt nicht verwendet, was eine Warnung auslöst. Wenn er jedoch der Variablen $result zugewiesen oder als void gecastet wird, gilt der Wert als verbraucht.

Die Autoren des RFC, der dieser Ergänzung zu PHP 8.5 zugrunde liegt, haben für dieses Attribut zwingendere Verwendungszwecke beschrieben als das einfache Beispiel oben. Ein Szenario war eine kritische Funktion mit einer komplexeren Fehlermeldung als einem einfachen Pass/Fail, die am besten durch den Rückgabewert der Funktion vermittelt wird.

Andere Verbesserungen in Bezug auf Attribute

Neben dem neuen Attribut #[NoDiscard] gibt es in der neuen Version noch weitere Verbesserungen der Attribut-Metadatenfunktionalität:

  • Attribute können jetzt auf Konstanten abzielen.
  • Das Attribut #[Override] kann jetzt auf Eigenschaften angewendet werden.
  • Das Attribut #[Deprecated] kann auf Eigenschaften und Konstanten angewendet werden.
  • Ein neues #[DelayedTargetValidation] Attribut kann verwendet werden, um Kompilierungsfehler von Kern- und Erweiterungsattributen zu unterdrücken, die auf ungültige Ziele angewendet werden.

Verwerfungen und Entfernungen in PHP 8.5

Mit jeder PHP-Version wird eine Liste von Funktionen veröffentlicht, die in zukünftigen Versionen entfernt werden sollen. Die Verwendung veralteter Funktionen in deinem Code führt zu Warnungen. Wenn sie schließlich aus PHP entfernt werden, kann ihre Verwendung zu fatalen Fehlern führen.

Hier sind einige bemerkenswerte Elemente, die in PHP 8.5 veraltet sind oder entfernt wurden:

  • Der Backtick-Operator als Alias für shell_exec() ist veraltet.
  • Die nicht-kanonischen Cast-Namen (boolean), (integer), (double) und (binary) sind veraltet. Verwende stattdessen (bool), (int), (float) und (string).
  • Die INI-Einstellung disable_classes wurde entfernt, da sie dazu führt, dass verschiedene Annahmen der Engine gebrochen werden.
  • Das Beenden von case Anweisungen mit einem Semikolon anstelle eines Doppelpunkts ist nicht mehr empfehlenswert.
  • Die Verwendung von Null als Array-Offset oder beim Aufruf von array_key_exists() ist jetzt veraltet. Verwende stattdessen einen leeren String.
  • Es ist nicht mehr möglich, „array“ und „callable“ als Klassenaliasnamen in class_alias() zu verwenden.
  • Die magischen Methoden __sleep() und __wakeup() sind jetzt veraltet. Stattdessen sollten die magischen Methoden __serialize() und __unserialize() verwendet werden.
  • Beim Casting von NAN in andere Typen wird jetzt eine Warnung ausgegeben.
  • Bei der Destrukturierung von Nicht-Array-Werten (außer Null) mit [] oder list() wird jetzt eine Warnung ausgegeben.
  • Beim Casting von Floats (oder Strings, die wie Floats aussehen) nach int wird jetzt eine Warnung ausgegeben, wenn sie nicht als Float dargestellt werden können.

Zusammenfassung

Das war ein Blick auf die Highlights der PHP 8.5 Version. Wir sind sicher, dass der neue Pipe-Operator und das verbesserte URI-Parsing bei den Entwicklern gut ankommen werden. Vielleicht sogar die neuen Funktionen array_first() und array_last(), auf die wir gewettet hätten, dass es sie schon gibt.

Aber jede neue PHP-Version umfasst Hunderte von Änderungen. Eine vollständige Liste der PHP 8.5 Updates findest du im offiziellen GitHub Repository der PHP Group.

In der Zwischenzeit arbeiten wir bei Kinsta daran, PHP 8.5 für unsere WordPress-Hosting-Kunden verfügbar zu machen. Sobald diese Version online ist, kannst du mit unseren PHP-Einstellungen auf die neue Version umsteigen.

Steve Bonisteel Kinsta

Steve Bonisteel is Technical Editor bij Kinsta. Hij begon zijn schrijverscarrière als verslaggever en achtervolgde ambulances en brandweerwagens. Sinds eind jaren negentig schrijft hij over internetgerelateerde technologie.