Ausblick auf PHP 8: Teil 1

PHP 8.0-Features im Fokus: Verbesserung der Typen
Keine Kommentare

Das Release von PHP 8 steht kurz bevor und mit ihm eine Reihe von Verbesserungen, neuen Funktionen und die generelle Überarbeitung, um die weit verbreitete serverseitige Websprache noch besser zu machen. In dieser Serie wollen wir darauf eingehen, was Sie über PHP 8 wissen sollten.

Der Countdown zum großen Release von PHP 8 ist bereits angebrochen. Die lang erwartete neue Version enthält eine ganze Reihe von neuen Funktionen und Verbesserungen, die den Entwicklern das Leben leichter machen sollen. In dieser Serie werfen wir einen Blick auf diese Neuerungen und was sie für die Nutzer bedeuten. Zunächst werden wir uns in diesem ersten Teil die verschiedenen Verbesserungen des Typensystems ansehen.

Union Types

Die größte Änderung des Typensystems ist die Einführung von Union Types. Sie sind ein virtueller Typ, der die „Union“ (ein logisches or) von zwei anderen Typen darstellt. Zum Beispiel:

<?php

function mangleUsers(string|array $users): array
{
    If (is_string($users)) {
        $users = [$users];
    }
    // ...
}

Wenn bisher der Parameterstil „einer oder viele“ unterstützt werden sollte, konnte der Parameter nicht eingegeben werden. Mit den nun getroffenen Änderungen kann einfach string|array angeben werden, wobei entweder eine String- oder eine Array-Variable akzeptiert wird. Integer, Objekte usw. werden weiterhin abgelehnt.

Union Types arbeiten mit Parametern, Rückgabetypen sowie Eigenschaftstypen und unterstützen alle von PHP unterstützten Typen: primitive, Objekte, benutzerdefinierte Klassen usw. Sie können verwendet werden, um alle Arten von unhandlichen, inkonsistenten APIs zu erzeugen. Das war zwar bereits früher schon möglich, doch jetzt können diese auch dokumentiert werden. Noch wichtiger ist, dass sich dadurch einige interessante Anwendungsfälle ergeben, die bisher im Typensystem selbst nicht dokumentiert werden konnten. Zum Beispiel kann eine Funktion, die eine Zahl benötigt und in der Lage ist, sowohl mit Ints als auch mit Floats zu arbeiten, jetzt genau das sagen:

<?php

function doMath(int|float): int|float
{
    // ...
}

Es ist nun auch möglich, ausdrücklich zu sagen, dass eine Funktion oder Methode Objekte unterschiedlichen Typs zurückgeben soll. Beispielsweise würde eine Funktion, die ein PSR-7-Anforderungsobjekt nimmt und entweder eine neue Anforderung oder eine entsprechende Antwort zurückgibt, so aussehen:

<?php

function handleRequest(RequestInterface $req): RequestInterface|ResponseInterface
{
    // ...
}

Bei der Vererbung folgen Union Types den gleichen kovarianten/kontravarianten Regeln wie jeder andere Typ. Das heißt, die Methodenparameter einer Unterklasse dürfen eine breitere Typdefinition als ihre Eltern akzeptieren (das Hinzufügen von |Foo ist also möglich, aber nicht das Entfernen), während ein Rückgabewert eine engere Typdefinition als seine Eltern angeben darf (das Entfernen von |Foo ist möglich, aber nicht das Hinzufügen).

Die Reflection API wurde ebenfalls aktualisiert, um die Überprüfung von Union Types auf Funktionen und Eigenschaften zu unterstützen.

Weitere Einzelheiten sind im ursprünglichen RFC verfügbar, vielen Dank an Nikita Popov dafür.

International PHP Conference

Passwords are so 1990

by Sam Bellen (Auth0)

Domain-Driven PHP

by Henning Schwentner (WPS – Workplace Solutions)

IT Security Summit 2020

Zero Trust – why are we having this conversation?

mit Victoria Almazova (Microsoft)

Digitaler Ersthelfer

mit Martin Wundram (DigiTrace GmbH)

Spezielle Unions

In PHP gibt es bereits eine Reihe von einmaligen Union Types, die in der Sprache definiert sind. iterable ist z. B. effektiv ein Union Type für array|\Traversable. Nullable-Typen, wie z.B. ?Product, sind im Wesentlichen ein Union Typ für null|Product. Tatsächlich ist es jetzt möglich, null als Typ in einer Union anzugeben – aber nicht nur dort. null|RequestInterface|ResponseInterface ist also eine akzeptierte Typdefinition. Das nullable Flag ? ist jetzt eine Abkürzung für null|, wenn nur ein einziger anderer Wert erlaubt ist.

Ein anderer reiner Union Type ist false. Er dient hauptsächlich der Unterstützung bestehender interner PHP-Funktionen, die aufgrund von Beurteilungsfehlern in den 1990er Jahren “a value, or false on error” zurückgeben. Diese Funktionen können nun eingegeben werden als:

<?php

function base64_decode(string $str, bool $strict = false): string|false {}

Diese Möglichkeit dient nur zur Unterstützung von Legacy-Code, der seine API nicht ändern kann. Bitte verwenden Sie sie nicht für neuen Code. Wie null kann false nicht als eigenständige Typdeklaration verwendet werden. Außerdem kann die void-Typdeklaration mit nichts kombiniert werden, da sie wörtlich bedeutet „es wird überhaupt nichts zurückgegeben, Punkt“, so dass es wenig Sinn ergibt, sie mit anderen Typen zu kombinieren.

PHP 8 führt auch einen neuen eingebauten Union Typ ein. Der neue mixed-Typ ist äquivalent zu array|bool|callable|int|float|null|object|resource|string. Das ist nicht ganz dasselbe, wie den Typ ganz wegzulassen. Das Weglassen könnte bedeuten, dass der Entwickler es einfach vergessen hat oder dass das Typsystem nicht robust genug ist, um die möglichen zulässigen Werte zu beschreiben. Die Verwendung des mixed-Typs sagt der Engine und anderen Programmierern ausdrücklich: „Ich akzeptiere hier alles, und das meine ich auch so“. Es gibt sehr wenige Fälle, in denen es nicht möglich ist, einen Parameter, eine Rückgabe oder eine Eigenschaft in PHP 8 einzugeben.

Vielen Dank an Máté Kocsis und Dan Ackroid für diesen RFC.

Das Stringable Interface

PHP-Objekte sind seit langem in der Lage, einen Weg zu definieren, wie sie mit Hilfe der __toString() magic method in einen String umgewandelt werden können. Der String-Typ Hint akzeptiert jedoch keine String-castable Objekte im Strict-Modus, was dies weniger nützlich macht, da PHP 7.0 skalare Typen eingeführt hat.

PHP 8 führt nun eine Stringable-Schnittstelle ein, die einem Objekt mit der __toString() magic method entspricht. Es tut dies auf eine clevere, rückwärtskompatible Weise.

Ab der Version 8.0 kann eine Klasse eine Stringable-Schnittstelle implementieren, die eine öffentliche Funktion der Methode __toString(): string definiert. Wenn dies nicht der Fall ist, diese Methode aber dennoch implementiert wird, fügt die Engine die Methode und den Rückgabetyp automatisch hinzu. Das bedeutet, dass nun jedes Stringable-Objekt typgeprüft werden kann, auch als Teil eines Union Typs, wie dies hier der Fall ist:

<?php

function show_message(string|Stringable $message): void
{
    // ...
}

Und Boom! __toString ist wieder nützlich.

Da das neue Interface technisch etwas strenger ist als die ursprüngliche __toString()-Methode (da sie einen String-Rückgabewert erzwingt und nicht nur annimmt), hat das Symfony-Team eine Polyfill dafür in ihr symfony/polyfill-php80-Paket aufgenommen. Das können Entwickler jetzt verwenden, um sicherzustellen, dass ihre Typen korrekt und sofort für PHP 8 vorwärtskompatibel sind.

Wohlgemerkt, nur weil __toString() jetzt besser nutzbar ist, heißt das nicht, dass man sie über die Maßen verwenden sollte. Die meisten Objekte sollten keine __toString()-Methode haben und stattdessen sinnvolle Methoden besitzen, die Strings zurückgeben. __toString() ist allerdings für Wertobjekte nützlich, die ausschließlich nur eine mögliche sinnvolle String-Repräsentation haben, weil das Objekt im Wesentlichen nur ein ausgefallener String ist. Ein gutes Beispiel ist ein IPv4Address-Objekt, bei dem es nur sinnvoll wäre, auf einen String als Strings vom Typ 1.2.3.4 zu casten.

Vielen Dank an Nicolas Grekas für den Stringable RFC.

Tipps und Tricks

Schließlich gibt es noch zwei weitere kleine Verbesserungen, die den alltäglichen Code erleichtern sollen. Erstens haben Objekte jetzt eine magische Konstante, die ihre Klasse angibt, genau wie Klassennamen. $object::class ist ein String, der den Klassennamen enthält, wie z. B. App\Form\FormDef. Es ist dasselbe wie get_class(), aber einfacher zu verwenden. Der Verdienst für diese Funktion geht auch hier an Nikita Popov.

Schließlich, als ein persönlicher Favorit, können Methoden jetzt einen static-Rückgabetyp haben. Das ist hauptsächlich für Interfaces mit verketteten Methoden nützlich. Das bedeutet, dass Folgendes jetzt möglich ist:

<?php

Interface TaskBuilder
{
    public function addStep(Step $s): static;
}

class  ImportantTask implements TaskBuilder 
{
    public function addStep(Step $s): static
    {
        $this->steps[] = $s;
        return $this;
    }
}

Nun wird ImportantTask::addStep() eingegeben, um eine Instanz von ImportantTask zurückzugeben. Mit einem Rückgabetyp von self wurde zuvor nur angezeigt, dass TaskBuilder zurückgegeben wird. Der Verdienst für diese Verbesserung geht wieder einmal an Nikita Popov. (Wir werden seinen Namen in dieser Serie noch oft lesen).

In der nächsten Woche betrachten wir uns dann match() expressions näher.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Abonnieren
Benachrichtige mich bei
guest
0 Comments
Inline Feedbacks
View all comments
X
- Gib Deinen Standort ein -
- or -