- Funktionen
- Pricing
PHP 8 bietet eine Vielzahl von Verbesserungen, neuen Funktionen und allgemeinen Optimierungen, um die beliebteste serverseitige Sprache im Web noch besser zu machen. Wir behandeln alles, was du über PHP 8 wissen musst. Es ist eine spannende Version, und wir werden nicht einmal alles abdecken können! Es gibt einfach so viel zu entdecken.
Zunächst gehen wir auf die verschiedenen Verbesserungen am Typsystem ein.
Die größte Änderung am Typsystem ist die Einführung von Union-Typen. Union-Typen sind virtuelle Typen, die die „Vereinigung“ (ein logisches „ODER“) zweier anderer Typen darstellen. Zum Beispiel:
<?php
function mangleUsers(string|array $users): array
{
If (is_string($users)) {
$users = [$users];
}
// ...
}Früher konntest du den Parameterstil „einer oder viele“ nicht typisieren, wenn du ihn so unterstützen wolltest. Jetzt kannst du string|array und entweder eine String- oder eine Array-Variable ist zulässig. Ganzzahlen, Objekte und so weiter werden weiterhin abgelehnt.
Union-Typen funktionieren bei Parametern, Rückgabetypen und Eigenschaftstypen und unterstützen jeden Typ, den PHP unterstützt: Primitive, Objekte, benutzerdefinierte Klassen usw. Zwar können sie dazu verwendet werden, alle möglichen unschönen, inkonsistenten APIs zu erzeugen, doch das war bereits zuvor möglich. Zumindest können sie nun dokumentiert werden. Noch wichtiger ist, dass sich dadurch einige interessante Anwendungsfälle eröffnen, die zuvor im Typsystem selbst nicht dokumentiert werden konnten.
Zum Beispiel kann eine Funktion, die eine Zahl benötigt, aber sowohl mit Ints als auch mit Floats arbeiten kann, das jetzt genau so ausdrücken:
<?php
function doMath(int|float): int|float
{
// ...
}Es ist auch möglich, explizit anzugeben, dass eine Funktion oder Methode Objekte unterschiedlicher Typen zurückgeben darf. Eine Funktion, die beispielsweise ein PSR-7-Request-Objekt entgegennimmt und entweder einen neuen Request oder eine entsprechende Response zurückgibt, würde so aussehen:
<?php
function handleRequest(RequestInterface $req): RequestInterface|ResponseInterface
{
// ...
}Bei der Vererbung folgen Vereinigungstypen denselben kovarianten/konvarianten Regeln wie jeder andere Typ. Das heißt, die Methodenparameter einer Unterklasse dürfen eine breitere Typdefinition akzeptieren als die ihrer übergeordneten Klasse (das Hinzufügen eines |Foo hinzuzufügen ist OK, es aber nicht zu entfernen), während ein Rückgabewert eine engere Typdefinition als der übergeordnete Typ angeben darf (also |Foo ist in Ordnung, das Hinzufügen jedoch nicht).
Die Reflection-API wurde ebenfalls aktualisiert, um die Überprüfung von Union-Typen bei Funktionen und Eigenschaften zu unterstützen.
Weitere Details findest du im ursprünglichen RFC. Vielen Dank an Nikita Popov für diesen Beitrag.
PHP verfügt bereits über eine Reihe von einmalig definierten Union-Typen in der Sprache. iterable, zum Beispiel, ist im Grunde ein Union-Typ für array|\Traversable. Nullable-Typen, wie ?Product, sind im Wesentlichen ein Vereinigungstyp von null|Product.
Tatsächlich ist es nun möglich, null als Typ in einer Vereinigung anzugeben, allerdings nur in einer Vereinigung. Somit null|RequestInterface|ResponseInterface ist eine zulässige Typdefinition. Das ? Nullable-Flag ist nun eine Kurzform für null| , wenn nur ein einziger anderer Wert zulässig ist.
Eine weitere Option, die nur für Union-Typen gilt, ist false. Das dient hauptsächlich dazu, bestehende interne PHP-Funktionen zu unterstützen, die aufgrund von Fehleinschätzungen aus den 1990er Jahren „einen Wert oder bei einem Fehler false“ zurückgeben. Diese Funktionen können nun wie folgt typisiert werden:
<?php
function base64_decode(string $str, bool $strict = false): string|false {}Diese Funktion dient ausschließlich der Unterstützung von Legacy-Programmen, deren API nicht verbessert werden kann. Bitte verwende sie nicht für neuen Code. Wie null, false kann nicht als eigenständige Typdeklaration verwendet werden. Außerdem lässt sich die void Typdeklaration kann mit nichts kombiniert werden, da sie wörtlich bedeutet „es wird überhaupt nichts zurückgegeben, Punkt“, daher macht es wenig Sinn, sie mit anderen Typen zu kombinieren.
PHP 8 führt außerdem einen neuen integrierten Union-Typ ein. Der neue mixed Typ entspricht array|bool|callable|int|float|null|object|resource|string. Das ist nicht ganz dasselbe wie das vollständige Weglassen des Typs. Das Weglassen des Typs 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 Types sagt man der Engine und anderen Entwicklern explizit: „Ich akzeptiere hier alles, und das meine ich auch so.“ Es gibt nun extrem wenige Fälle, in denen es in PHP 8 nicht möglich ist, einen Parameter, einen Rückgabewert oder eine Eigenschaft zu typisieren.
Vielen Dank an Máté Kocsis und Dan Ackroid für diesen RFC.
PHP-Objekte können schon seit langem mithilfe der magischen Methode __toString() festlegen, wie sie in einen String umgewandelt werden können. Der string Typ-Hinweis akzeptiert im strengen Modus keine Objekte, die in Strings umgewandelt werden können, was dies seit der Einführung von Skalar-Typen in PHP 7.0 weniger nützlich macht.
PHP 8 führt nun eine Stringable Schnittstelle ein, die einem Objekt entspricht, das über die __toString() magischen Methode. Dies geschieht zudem auf clevere, abwärtskompatible Weise.
Ab Version 8.0 kann eine Klasse eine Stringable Schnittstelle implementieren, die eine Methode public function __toString(): string. Tut sie das nicht, implementiert aber dennoch diese Methode, fügt die Engine die Methode und den Rückgabetyp automatisch hinzu. Das bedeutet, dass jedes stringable Objekt nun typgeprüft werden kann, auch als Teil eines Union-Typs, etwa so:
<?php
function show_message(string|Stringable $message): void
{
// ...
}Bumm! __toString ist wieder nützlich.
Da die neue Schnittstelle technisch gesehen etwas strenger ist als die ursprüngliche __toString() (da sie eine String-Rückgabe erzwingt, anstatt sie nur anzunehmen), hat das Symfony-Team ein Polyfill dafür in sein symfony/polyfill-php80-Paket aufgenommen. So können Entwickler es ab sofort nutzen, um sicherzustellen, dass ihre Typen korrekt sind und sofort vorwärtskompatibel für PHP 8 sind.
Aber nur weil __toString() jetzt besser nutzbar ist, heißt das nicht, dass du es übertreiben solltest. Die meisten Objekte sollten keine __toString() Methode haben und stattdessen sinnvolle Methoden besitzen, die Strings zurückgeben. Wo __toString() ist nützlich für Wert-Objekte, die genau eine sinnvolle String-Darstellung haben, da das Objekt im Grunde nur ein ausgefallener String ist. Ein gutes Beispiel ist ein IPv4Address Objekt, bei dem es nur Sinn macht, es in einen String vom Typ 1.2.3.4 Typ „String“
Danke an Nicolas Grekas für den Stringable-RFC.
Schließlich gibt es noch zwei weitere kleine Verbesserungen, die das Programmieren täglich erleichtern.
Erstens haben Objekte jetzt eine magische Konstante, die ihre Klasse angibt, genau wie Klassennamen. $object::class ist eine Zeichenkette, die den Klassennamen enthält, zum Beispiel App\Form\FormDef. Das ist dasselbe wie get_class(), ist aber einfacher zu verwenden. Der Dank für diese Feature geht erneut an Nikita Popov.
Und schließlich, mein persönlicher Favorit: Methoden können jetzt den Rückgabetyp static. Das ist vor allem für Schnittstellen mit verketteten Methoden nützlich. Das bedeutet, dass Folgendes nun 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;
}
}Und nun ImportantTask::addStep() wird so typisiert, dass es eine Instanz von ImportantTask. Zuvor hätte ein Rückgabetyp von self hätte das nur bedeutet, dass TaskBuilder.
Der Dank für diese Verbesserung geht wieder einmal an Nikita Popov. (Seinen Namen wirst du in dieser Serie noch oft sehen.)
Nützliche Links: