Hoe de nieuwe kruispunttypen in PHP 8.1 u meer flexibiliteit geven

0
166

Intersectietypes zijn een nieuw type systeemfunctie in PHP 8.1. Hiermee kunt u waarden typen die aan meer dan één typebeperking moeten voldoen. PHP’s hebben al union-types die typen combineren met een logische “of” clausule; kruispunttypen bieden een “en” clausule in plaats daarvan.

Sommige ontwikkelaars typen al kruisingen met behulp van PHPDoc-annotaties. De toevoeging van native ondersteuning is een stap voorwaarts, aangezien de typen daadwerkelijk tijdens runtime worden afgedwongen. Ze zijn ook volledig compatibel met klasse-overerving, waardoor het risico op fouten als gevolg van verouderde of incompatibele annotaties wordt verminderd.

Basissyntaxis

De kruising type syntaxis is vergelijkbaar met union-types:

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

In dit voorbeeld wordt aan $Union voldaan door elke waarde die Countable of Stringable is. $Intersection accepteert alleen waarden die aan beide beperkingen voldoen. Je krijgt een TypeError als je aan de eigenschap een waarde toewijst die een of nul van de hinttypes implementeert.

Intersectietypes worden overal ondersteund waar typehints werken. U kunt ze gebruiken met eigenschapsdefinities, functieparameters en retourwaarden.

In tegenstelling tot vakbondstypen, kunnen intersecties alleen interfaces en klassen typen. Een scalair snijpunt zoals int&string is zinloos omdat er nooit aan kan worden voldaan. Het gemengde type is ook verbannen, omdat elke waarde aan zijn beperking zal voldoen.

Typevariantie

Typen kruispunten respecteren de bestaande variantieregels van PHP. De retourtypen van overschreven methoden moeten covariant zijn, terwijl parametertypen contravariant zijn. Klasse-eigenschappen zijn altijd invariant, dus kinderen kunnen de typedefinitie niet wijzigen tenzij de nieuwe handtekening zowel een subtype als een supertype is van het geërfde.

Advertentie

Voor retourwaarden gelden de variantieregels betekent dat u extra typen kruispunten kunt toevoegen aan overschreven methoden. Methoden kunnen ook typen verwijderen, maar niet toevoegen aan kruispunten die als parameters worden gebruikt. Deze regels dwingen het vervangingsprincipe van Liskov af.

interface I1 { publieke functie methode1(A&B $demo) : X&Y; publieke functiemethode2(A&B $demo) : X&Y; }   interface I2 breidt I1 uit {   //TOEGESTAAN publieke functie methode1(A $demo) : X&Y&Z;   //NIET TOEGESTAAN publieke functiemethode2(A&B&C $demo) : X;   }

In het geval van methode 1 zijn de beperkingen eigenlijk niet veranderd. Je geeft aan dat de overschreven methode met elke A kan werken, zelfs als het niet ook een X is. Het is minder specifiek, wat resulteert in acceptabele parametervariantie. De aangifte aangifte is specifieker, met vermelding van de waarde zal X, Y en Z implementeren; in dit scenario verbreekt het toevoegen van specificiteit het contract niet, omdat de waarde nog steeds wordt geaccepteerd door alles wat I1 typeert.

De methode2-overschrijving is in beide opzichten verbroken. Door te eisen dat de invoerparameter aan A, B en C voldoet, is het niet langer een vervanging voor I1. Evenzo garandeert methode2 alleen dat de geretourneerde waarde een instantie van X zal zijn. Dit verbreekt het contract, aangezien alles wat op I1 duidt, de waarde vereist om te voldoen aan de kruising van X en Y.

Snijpunten keren de praktische variantieregels van vakbondstypen om. Aangezien vakbonden worden gecombineerd met “of,” kinderen kunnen parametertypen toevoegen en retourtypen verwijderen. Aan het Liskov-substitutieprincipe wordt voldaan als het verbredende en vernauwende effect van de typebeperkingen wordt omgekeerd.

Net als bij vakbondstypen, zijn variantieregels ook van toepassing op de typen waaruit een kruispunt bestaat – dat zijn de individuele X- en Y-delen van X&Y. U kunt een type verfijnen wanneer u het retourneert – waarin staat dat u een subklasse – of verbreed het als een parameter en accepteer een superklasse.

Advertentie

Intersecties hebben ook enkele speciale regels rond aliasing en concrete implementaties. Als je X&Y typt maar een interface schrijft die Z X, Y uitbreidt, is het logisch dat Z aan de beperking voldoet. U kunt dus Z typen in plaats van X&Y waar co-variantie is toegestaan:

interface Test verlengt X, Y {}   interface Demo1 { publieke functiedemo() : X&Y; }   interface Demo2 { publieke functie demo() : Toets; }

Hiermee kunt u een concrete klasse of interface typen als u afhankelijk bent van extra functionaliteit. Het is acceptabel zolang aan alle beperkingen in de kruising wordt voldaan door de laatste typhint.

Wanneer kruisingstypes gebruiken?

Wanneer kruispunttypes gebruiken?

Typen kruispunten zijn voor de momenten waarop u er zeker van wilt zijn dat een waarde voldoet aan een samengestelde interface zonder die interface daadwerkelijk te definiëren. Eerdere PHP-versies boden hiervoor geen native ondersteuning, dus je moest een hoop extra boilerplate aan je codebase toevoegen:

interface CountableStringable breidt Countable, Stringable uit { //… }   klasse FakeArray implementeert CountableStringable {   openbare array $items = [];   publieke functie tellen() : int { return count($this -> artikelen); }   publieke functie __toString() : tekenreeks { return implode(", ", $this -> artikelen); }   }   klasse DemoClass {   openbare CountableStringable $ Waarde;   }

Dit leidt tot een overmaat aan stub-achtige ondiepe interfaces om basis kruispuntgedrag te bereiken. Hoewel PHP-ontwikkelaars tot nu toe zonder kruispunten hebben overleefd, helpt hun aanwezigheid de samengestelde mogelijkheden van het typesysteem te versterken. Het gebruik van native intersecties zorgt voor schonere en intuïtievere code.

Hoe zit het met samengestelde typen?

Het is niet mogelijk om intersectie- en verbindingstypen in dezelfde typhint te combineren. Hoewel het technisch mogelijk zou zijn, is het weggelaten uit de huidige RFC omdat er onduidelijkheden zijn rond syntaxis, prioriteit en variantie.

Samengestelde typen blijven een idee voor de toekomst. Als ze waren toegevoegd, zou je kunnen beginnen met het toevoegen van complexe typehints zoals deze:

klasse DemoClass {   public Countable&Stringable|CountableStringable $Intersection;   } Advertentie

Deze voorbeeldklasse combineert de twee bovenstaande implementaties. Als het zou werken, zou het je in staat stellen om native kruispunttypen over te nemen terwijl je achterwaartse compatibiliteit met oude klassen behoudt met behulp van de “nep” benadering.

Volledige composiettypen zouden de meervoudige typebehandeling voltooien die wordt vergemakkelijkt door vakbonden en kruispunten. In de tussentijd moet je in deze scenario's je eigen samengestelde interfaces blijven schrijven.

Samenvatting

Intersectietypen komen naar PHP 8.1 en zullen ontgrendel meer geavanceerde mogelijkheden binnen het typesysteem. Het uitbreiden van de opties rond samengestelde typen vermindert de hoeveelheid code die u moet schrijven wanneer meerdere interfaces worden ondersteund.

Intersecties zijn een optionele functie die geen incompatibiliteit met bestaande code introduceert. De RFC is geïmplementeerd in de derde PHP 8.1 alpha build. De definitieve release komt eind november later dit jaar uit.