Wie die neuen Kreuzungstypen in PHP 8.1 Ihnen mehr Flexibilität bieten

0
68

Kreuzungstypen sind eine neue Typsystemfunktion in PHP 8.1. Sie ermöglichen die Eingabe von Hinweiswerten, die mehr als eine Typeinschränkung erfüllen müssen. PHP hat bereits Union-Typen, die Typen mit einem logischen “oder” Klausel; Kreuzungstypen bieten ein “und” Klausel stattdessen.

Einige Entwickler geben bereits Überschneidungen mit PHPDoc-Annotationen ein. Das Hinzufügen der nativen Unterstützung ist ein Fortschritt, da die Typen tatsächlich zur Laufzeit erzwungen werden. Sie sind auch vollständig mit der Klassenvererbung kompatibel, wodurch das Risiko von Fehlern aufgrund veralteter oder inkompatibler Anmerkungen verringert wird.

Grundsyntax

Die Schnittmenge type-Syntax ähnelt Union-Typen:

class DemoClass {   public Countable|Stringable $Union;   public Countable&Stringable $Intersection;   }

In diesem Beispiel wird $Union von jedem Wert erfüllt, der entweder Countable oder Stringable ist. $Intersection akzeptiert nur Werte, die beide Einschränkungen erfüllen. Sie erhalten einen TypeError, wenn Sie der Eigenschaft einen Wert zuweisen, der einen oder null der Hinted-Typen implementiert.

Intersection-Typen werden überall dort unterstützt, wo Typehints funktionieren. Sie können sie mit Eigenschaftsdefinitionen, Funktionsparametern und Rückgabewerten verwenden.

Im Gegensatz zu Union-Typen können Schnittmengen nur Schnittstellen und Klassen eingeben. Eine skalare Schnittmenge wie int&string ist bedeutungslos, da sie niemals erfüllt werden könnte. Der gemischte Typ ist ebenfalls verboten, da jeder Wert seine Einschränkung erfüllt.

Typvarianz

Kreuzungstypen respektieren die bestehenden Varianzregeln von PHP. Die Rückgabetypen überschriebener Methoden müssen kovariant sein, während Parametertypen kontravariant sind. Klasseneigenschaften sind immer invariant, daher können Kinder die Typdefinition nicht ändern, es sei denn, die neue Signatur ist sowohl ein Untertyp als auch ein Supertyp des geerbten.

Werbung

Für Rückgabewerte gelten die Varianzregeln bedeutet, dass Sie in überschriebenen Methoden zusätzliche Schnittpunkttypen hinzufügen können. Methoden können auch Typen von Schnittpunkten entfernen, aber nicht hinzufügen, die als Parameter verwendet werden. Diese Regeln erzwingen das Liskov-Substitutionsprinzip.

Schnittstelle I1 { öffentliche Funktion method1(A&B $demo) : X&Y; öffentliche Funktion method2(A&B $demo) : X&Y; }   Schnittstelle I2 erweitert I1 {   //ERLAUBT öffentliche Funktion method1(A $demo) : X&Y&Z;   //NICHT ERLAUBT öffentliche Funktion method2(A&B&C $demo) : X;   }

Im Fall von method1 haben sich die Einschränkungen nicht geändert. Sie geben an, dass die überschriebene Methode tatsächlich mit jedem A funktionieren kann, auch wenn es nicht gleichzeitig ein X ist. Sie ist weniger spezifisch, was zu einer akzeptablen Parametervarianz führt. Die Rückgabedeklaration ist genauer, die Angabe des Werts implementiert X, Y und Z; In diesem Szenario verletzt das Hinzufügen von Spezifität den Vertrag nicht, da der Wert immer noch von allem akzeptiert wird, das I1 eintippt.

Die Überschreibung von method2 wird in beiden Fällen gebrochen. Da der Eingabeparameter A, B und C erfüllen muss, ist er kein Ersatz für I1 mehr. In ähnlicher Weise garantiert method2 nur, dass der Rückgabewert eine Instanz von X ist. Dies bricht den Vertrag, da alles, was auf I1 tippt, den Wert erfordert, um die Schnittmenge von X und Y zu erfüllen.

Schnittmengen invertieren die praktischen Varianzregeln von Unionstypen. Da Unions mit “oder” Kinder können Parametertypen hinzufügen und Rückgabetypen entfernen. Das Liskov-Substitutionsprinzip wird erfüllt, da der erweiternde und verengende Effekt der Typbeschränkungen umgekehrt wird.

Wie bei Vereinigungstypen gelten Varianzregeln auch für die Typen, die eine Schnittmenge bilden – das sind die einzelnen X- und Y-Teile von X&Y. Sie können einen Typ bei der Rückgabe eingrenzen – geben an, dass Sie eine Unterklasse zurückgeben – oder als Parameter erweitern und eine Superklasse akzeptieren.

Werbung

Schnittpunkte besitzen auch einige spezielle Regeln für Aliasing und konkrete Implementierungen. Wenn Sie den Hinweis X&Y eingeben, aber eine Schnittstelle schreiben, die Z X, Y erweitert, ist es logisch, dass Z die Einschränkung erfüllt. Folglich können Sie überall dort, wo Kovarianz zulässig ist, Z anstelle von X und Y eingeben:

Schnittstellentest erweitert X, Y {}   Schnittstelle Demo1 { Demo für öffentliche Funktionen() : X&Y; }   Schnittstelle Demo2 { Demo für öffentliche Funktionen() : Prüfen; }

Damit können Sie eine konkrete Klasse oder Schnittstelle eingeben, wenn Sie auf zusätzliche Funktionalität angewiesen sind. Dies ist akzeptabel, solange alle Einschränkungen in der Schnittmenge durch den endgültigen Typhint erfüllt werden.

Wann sollten Schnittmengentypen verwendet werden?

Schnittmengentypen sind für den Fall gedacht, dass ein Wert eine zusammengesetzte Schnittstelle erfüllt, ohne diese Schnittstelle tatsächlich zu definieren. Frühere PHP-Versionen boten hierfür keine native Unterstützung, daher mussten Sie Ihrer Codebasis eine Menge zusätzlicher Boilerplate hinzufügen:

Schnittstelle CountableStringable erweitert Countable, Stringable { //… }   Klasse FakeArray implementiert CountableStringable {   öffentliches Array $items = [];   Anzahl der öffentlichen Funktionen() : int { Rücklaufanzahl($this -> Artikel); }   öffentliche Funktion __toString() : Zeichenfolge { return implode(", ", $this -> Artikel); }   }   Klasse DemoKlasse {   public CountableStringable $Value;   }

Dies führt zu einem Überschuss an stummelartigen flachen Schnittstellen, um ein grundlegendes Kreuzungsverhalten zu erreichen. Obwohl PHP-Entwickler bis heute ohne Schnittmengen überlebt haben, trägt ihre Anwesenheit dazu bei, die zusammengesetzten Fähigkeiten des Typsystems zu festigen. Die Verwendung nativer Schnittmengen erzeugt einen saubereren und intuitiveren Code.

Was ist mit zusammengesetzten Typen?

Es ist nicht möglich, Schnittmengen- und Vereinigungstypen im selben Typhint zu kombinieren. Obwohl es technisch möglich wäre, wurde es im aktuellen RFC weggelassen, da es Unklarheiten in Bezug auf Syntax, Rangfolge und Varianz gibt.

Zusammengesetzte Typen bleiben eine Idee für die Zukunft. Wenn sie hinzugefügt wurden, könnten Sie damit beginnen, komplexe Typhinweise wie folgt hinzuzufügen:

Klasse DemoKlasse {   public Countable&Stringable|CountableStringable $Intersection;   } Werbung

Diese Beispielklasse kombiniert die beiden oben genannten Implementierungen. Wenn es funktionierte, könnten Sie native Schnittmengentypen übernehmen, während die Abwärtskompatibilität mit alten Klassen mit dem “fake” Ansatz.

Vollwertige zusammengesetzte Typen würden die Handhabung mehrerer Typen abrunden, die durch Vereinigungen und Schnittmengen erleichtert wird. In der Zwischenzeit müssen Sie in diesen Szenarien weiterhin Ihre eigenen zusammengesetzten Schnittstellen schreiben.

Zusammenfassung

Kreuzungstypen kommen in PHP 8.1 und werden schalten Sie erweiterte Möglichkeiten innerhalb des Typensystems frei. Das Erweitern der Optionen um zusammengesetzte Typen reduziert die Menge an Code, die Sie schreiben müssen, wenn mehrere Schnittstellen unterstützt werden.

Überschneidungen sind eine optionale Funktion, die keine Inkompatibilitäten mit bestehendem Code einführt. Der RFC wurde im dritten PHP 8.1 Alpha-Build implementiert. Die endgültige Veröffentlichung wird Ende November dieses Jahres eintreffen.