PHP 8.3 wurde pünktlich am 23. November veröffentlicht und enthält viele neue Funktionen und Verbesserungen seit der Einführung von PHP 8.2. Auch wenn es sich offiziell um eine kleinere Version handelt, könnten sich einige der Änderungen in 8.3 direkt auf deine Arbeit mit PHP auswirken – und dir vielleicht helfen, schneller und mit weniger Fehlern zu programmieren.

Werfen wir einen Blick auf die großen – und manchmal auch nicht so großen – Änderungen, die mit dieser neuen Version einhergehen.

Neue Funktionen und Verbesserungen in PHP 8.3

Beginnen wir mit den Funktionen von PHP 8.3, die die meisten Schlagzeilen machen.

Typisierte Klassenkonstanten

Die Möglichkeit, Typen für Klasseneigenschaften zu deklarieren, steht uns seit PHP 7.4 zur Verfügung. Doch trotz zahlreicher Verbesserungen der PHP-Typisierung im Laufe der Jahre wurde sie nicht auf Konstanten ausgeweitet – bis jetzt.

Klassenkonstanten – und dazu gehören auch Interface-, Trait- und Enum-Konstanten – können in PHP 8.3 typisiert werden, so dass es unwahrscheinlicher wird, dass Entwickler/innen von der Absicht abweichen, die hinter der ursprünglichen Deklaration einer Konstante steht.

Hier ist ein einfaches Beispiel mit einer Schnittstelle:

// Legal:
interface ConstTest {
    // Declared type and value are both strings
    const string VERSION = "PHP 8.3";
}

// Illegal:
interface ConstTest {
    // Type and value mismatch in this initial declaration
    const float VERSION = "PHP 8.3";
}

Der wahre Wert dieser typisierten Klassenkonstanten zeigt sich bei der Arbeit in Klassen, die von den Basisdeklarationen abgeleitet sind. Während eine Childclass einer Konstante häufig einen neuen Wert zuweisen kann, kann PHP 8.3 verhindern, dass der Typ der Konstante versehentlich geändert wird, so dass sie nicht mehr mit der ursprünglichen Deklaration kompatibel ist:

class ConstTest {
    const string VERSION = "PHP 8.2";
}

class MyConstTest extends ConstTest {

    // Legal:
    // It's OK to change the value of VERSION here
    const string VERSION = "PHP 8.3";

    // Illegal:
    // Type must be declared if it was specified in the base class
    const VERSION = "PHP 8.3";

    // Illegal:
    // In this case, we can't change the type declared in the 
    // base class, even if the new type and its value are compatible.
    const float VERSION = 8.3;
}

Denke daran, dass der Typ, der einer Klassenkonstante zugewiesen wird, variieren kann, wenn mehrere Typen „eingegrenzt“ oder ein ansonsten kompatibler Typ verwendet wird:

class ConstTest {
    const string|float VERSION = "PHP 8.2";
}

class MyConstTest extends ConstTest {

    // Legal:
    // Here, it's OK to narrow the type declaration to string or float
    const string VERSION = "PHP 8.3";
    const float VERSION = 8.3;

    // Legal:
    // Value could be an int, but it's compatible with float 
    const float VERSION = 8;

    // Illegal:
    // We can't widen the type options here to include int
    const string|float|int VERSION = 8;
}

Zwei Typen, die für andere Eigenschaften bei der Validierung von Rückgabewerten unterstützt werden – void und never – werden nicht als Klassenkonstanten-Typen unterstützt.

Eine neue json_validate() Funktion

Wenn du mit JSON-kodierten Daten arbeitest, ist es gut zu wissen, ob die Nutzdaten syntaktisch gültig sind, bevor du versuchst, etwas mit ihnen zu machen.

In früheren PHP-Versionen haben Entwickler die Funktion json_decode() verwendet und auf Fehler geprüft, während diese Funktion versucht hat, JSON-Daten in assoziative Arrays oder Objekte zu verwandeln. Die neue Funktion von PHP 8.3 json_validate() Funktion führt die Fehlerprüfung durch, ohne den gesamten Speicher zu verbrauchen, der zum Aufbau dieser Array- oder Objektstrukturen erforderlich ist.

In der Vergangenheit hättest du also eine JSON-Nutzlast etwa so validieren können:

$obj = json_decode($maybeJSON);

if (json_last_error() === JSON_ERROR_NONE) {
    // Probably do something with $obj   
}

Wenn du im obigen Beispiel nicht sofort etwas mit $obj machen willst, werden eine Menge Ressourcen verbraucht, nur um die Gültigkeit der ursprünglichen JSON-Nutzdaten zu bestätigen. In PHP 8.3 kannst du so etwas tun und etwas Speicher sparen:

if (json_validate($maybeJSON)) {
    // Do something with $maybeJSON   
}

Hinweis: Es macht nicht viel Sinn, json_validate() zu verwenden und die Daten dann sofort durch json_decode() laufen zu lassen, wobei die Speicherressourcen von decode sowieso verbraucht werden. Es ist wahrscheinlicher, dass du die neue Funktion verwendest, um das JSON zu validieren, bevor du es irgendwo speicherst oder als Antwort auf eine Anfrage übermittelst.

Deep Cloning von readonly Eigenschaften

Die Möglichkeit, einzelne Klasseneigenschaften als readonly zu deklarieren, wurde in PHP 8.1 eingeführt. Mit PHP 8.2 wurde die Möglichkeit eingeführt, dieses Attribut einer ganzen Klasse zuzuweisen. Viele Entwickler waren jedoch der Meinung, dass die Einschränkungen bei der Arbeit mit Klassen, die solche Eigenschaften enthalten, einer sinnvollen Programmierung im Wege stehen.

In einem RFC zur Änderung des Verhaltens von readonly wurden zwei Vorschläge gemacht:

  1. Erlaube Klassen, die nicht readonly sind, Klassen zu erweitern
  2. Erlaube, dass die Eigenschaften von readonly beim Klonen reinitialisiert werden

Der zweite Vorschlag hat es in PHP 8.3 geschafft. Der neue Ansatz erlaubt es, Instanzen einer Klasse mit readonly Eigenschaften innerhalb der __clone magic Methode zu reinitialisieren (auch über Funktionen, die von __clone aus aufgerufen werden).

Dieses Codebeispiel aus dem RFC zeigt, wie es funktioniert:

class Foo {
    public function __construct(
        public readonly DateTime $bar,
        public readonly DateTime $baz
    ) {}
 
    public function __clone() {
        // $bar will get a new DateTime when clone is invoked
        $this->bar = clone $this->bar; 

        // And this function will be called
        $this->cloneBaz();
    }
 
    private function cloneBaz() {
       // This is legal when called from within __clone
        unset($this->baz); 
    }
}
 
$foo = new Foo(new DateTime(), new DateTime());
$foo2 = clone $foo;

Neues #[\Override] Attribut

Bei der Implementierung von Schnittstellen in PHP stellen Programmierer detaillierte Funktionen für die in diesen Schnittstellen genannten Methoden bereit. Bei der Erstellung einer Instanz einer Klasse können Programmierer eine übergeordnete Methode außer Kraft setzen, indem sie eine alternative Version mit demselben Namen und einer kompatiblen Signatur in der Child-Klasse erstellen.

Ein Problem besteht darin, dass Programmierer denken könnten, dass sie eine Schnittstellenmethode implementieren oder eine übergeordnete Methode außer Kraft setzen, obwohl sie es nicht tun. Es kann sein, dass sie eine völlig neue Methode erstellen, weil sie sich im Namen der Child-Methode vertippt haben oder weil die Methoden im Code der Parent-Klasse entfernt oder umbenannt wurden.

PHP 8.3 führt das Attribut #[\Override] ein, um Programmierern zu helfen, deutlich zu machen, dass eine Methode eine gewisse Abstammung innerhalb des Codes haben muss.

Hier ist ein einfaches Beispiel:

class A {
    protected function ovrTest(): void {}
}

// This will work because ovrTest() 
// can be found in the parent class
class B extends A {
    #[\Override]
    public function ovrTest(): void {}
}

// This will fail because ovrBest() 
// (probably a typo) is not in the parent
class C extends A {
    #[\Override]
    public function ovrBest(): void {}
}

Dynamische Abfrage von Klassenkonstanten und Enum-Mitgliedern

Anders als bei anderen Eigenschaften im PHP-Code war das Abrufen von Klassenkonstanten und Enum-Mitgliedern mit Variablennamen bisher etwas umständlich. Vor PHP 8.3 konntest du das mit der Funktion constant() wie folgt machen:

class MyClass {
    public const THE_CONST = 9;
}

enum MyEnum int {
    case FirstMember = 9;
    case SecondMember = 9;
}

$constantName = 'THE_CONST';
$memberName = 'FirstMember';

echo constant('MyClass::' . $constantName);
echo constant('MyEnum::' . $memberName)->value;

Mit denselben Klassen- und Enum-Definitionen wie oben kannst du jetzt das gleiche Ergebnis mit dem dynamischen Abrufen von Konstanten in PHP 8.3 erreichen:

$constantName = 'THE_CONST';
$memberName = 'FirstMember';

echo MyClass::{$constantName};
echo MyEnum::{$memberName}->value;

Neue getBytesFromString() Methode

Wolltest du schon einmal zufällige Zeichenketten aus einer vorher festgelegten Sammlung von Zeichen erzeugen? Das kannst du jetzt ganz einfach mit der getBytesFromString() Methode, die der Erweiterung Random in PHP 8.3 hinzugefügt wurde.

Diese neue Methode ist einfach: Du übergibst ihr eine Zeichenkette als Ausgangsmaterial und gibst an, wie viele davon du verwenden möchtest. Die Methode wählt dann nach dem Zufallsprinzip Bytes aus der Zeichenkette aus, bis sie die angegebene Länge erreicht.

Hier ist ein einfaches Beispiel:

$rando = new Random\Randomizer();
$alpha = 'ABCDEFGHJKMNPQRSTVWXYZ';

$rando->getBytesFromString($alpha, 6); //  "MBXGWL"
$rando->getBytesFromString($alpha, 6); //  "LESPMG"
$rando->getBytesFromString($alpha, 6); //  "NVHWXC"

Es ist möglich, dass die angeforderte Länge der zufälligen Ausgabe mehr Bytes hat als der Eingangsstring:

$rando = new Random\Randomizer();
$nums = '123456';

$rando->getBytesFromString($nums, 10); //  "2526341615"

Bei einer Eingabekette mit eindeutigen Zeichen hat jedes Zeichen die gleiche Chance, für das Zufallsergebnis ausgewählt zu werden. Allerdings können Zeichen gewichtet werden, indem sie häufiger als andere in der Eingabe vorkommen. Ein Beispiel:

$rando = new Random\Randomizer();
$weighted = 'AAAAA12345';

$rando->getBytesFromString($weighted, 5); //  "1AA53"
$rando->getBytesFromString($weighted, 10); //  "42A5A1AA3A"

Neue Methoden getFloat() und nextFloat()

Als Erweiterung der Random-Erweiterung führt PHP 8.3 zwei neue Methoden zur Erzeugung zufälliger Float-Werte ein: getFloat() und nextFloat().

Hier ist ein Beispiel:

$rando = new Random\Randomizer();

// Generate a float value between a minimum 
//  value of 0 and a maximum value of 5
$rando->getFloat(0,5); // 2.3937446906217

Die Methode getFloat() akzeptiert neben dem Minimal- und Maximalwert auch einen dritten Parameter. Mit einer Random\IntervalBoundary Enum kann man festlegen, ob die Min- und Max-Werte selbst von der Funktion zurückgegeben werden können.

Hier sind die Regeln:

  • IntervalBoundary::ClosedOpen: min darf zurückgegeben werden, aber nicht max
  • IntervalBoundary::ClosedClosed: sowohl min als auch max dürfen zurückgegeben werden
  • IntervalBoundary::OpenClosed: min darf nicht zurückgegeben werden, max schon
  • IntervalBoundary::OpenOpen: weder min noch max dürfen zurückgegeben werden

Wenn du getFloat() verwendest, ohne die Enum als dritten Parameter anzugeben, ist der Standardwert IntervalBoundary::ClosedOpen.

Ein nützliches Beispiel aus der Dokumentation der neuen Funktion erzeugt zufällige Längen- und Breitenkoordinaten, wobei die Breitengrade -90 und 90 enthalten können, die Längengrade aber nicht -180 und 180 (da sie gleich sind):

$rando = new Random\Randomizer();

printf(
    "Lat: %+.6f Long: %+.6f",
    $rando->getFloat(-90, 90, \Random\IntervalBoundary::ClosedClosed),

    // -180 will not be used 
    $rando->getFloat(-180, 180, \Random\IntervalBoundary::OpenClosed),
);

Die neue Methode nextFloat() ist im Wesentlichen dasselbe wie getFloat(), um einen Zufallswert abzufragen, der von 0 bis kleiner als 1 reicht:

$rando = new Random\Randomizer();

$rando->nextFloat(); // 0.3767414902847

Weitere kleinere Änderungen in PHP 8.3

PHP 8.3 enthält auch eine Reihe anderer neuer Funktionen und kleinerer Änderungen. Wir erwähnen sie im Folgenden mit Links zu zusätzlichen Ressourcen (sofern verfügbar):

Auslaufende Funktionen in PHP 8.3

Mit jeder neuen Version von PHP werden einige Funktionen und Einstellungen als veraltet gekennzeichnet, damit sie entfernt werden können. Sobald diese Funktionen veraltet sind, werden sie nicht mehr empfohlen und führen zu Hinweisen in vielen Logs, wenn sie in ausführbarem Code erscheinen.

Hier findest du eine Liste der veralteten Funktionen in PHP 8.3 mit Links zu weiteren Informationen:

Zusammenfassung

Wir haben uns die wichtigsten Änderungen in PHP 8.3 angesehen. Eine detaillierte Liste aller Neuerungen in dieser Version findest du im offiziellen Changelog der Version. Wenn du vorhast, deinen Code auf eine Plattform zu verschieben, auf der die neueste PHP-Version läuft, kann dir der 8.2-zu-8.3-Migrationsleitfaden helfen, Probleme zu vermeiden.

Wenn es deine Aufgabe ist, PHP auf deinen Entwicklungs- oder Produktionsservern zu installieren, steht 8.3 jetzt zum Download bereit.

Wenn du Kinsta-Kunde bist, kannst du dich darauf verlassen, dass wir diese Version auf den Servern hinter deinen Managed WordPress Hosting- oder Application Hosting-Projekten zur Verfügung stellen.

Steve Bonisteel Kinsta

Steve Bonisteel is a Technical Editor at Kinsta who began his writing career as a print journalist, chasing ambulances and fire trucks. He has been covering Internet-related technology since the late 1990s.