Comment les nouveaux types d'intersection dans PHP 8.1 vous offrent plus de flexibilité - CloudSavvy IT
Agence web » Actualités du digital » Comment les nouveaux types d’intersection dans PHP 8.1 vous offrent plus de flexibilité –

Comment les nouveaux types d’intersection dans PHP 8.1 vous offrent plus de flexibilité –

Les types d’intersection sont une nouvelle fonctionnalité du système de types à venir dans PHP 8.1. Ils vous permettent de saisir des valeurs qui doivent satisfaire plusieurs contraintes de type. PHP a déjà des types d’union qui combinent des types avec une clause « ou » logique; les types d’intersection offrent à la place une clause « et ».

Certains développeurs tapent déjà des intersections à l’aide d’annotations PHPDoc. L’ajout du support natif est un pas en avant car les types seront effectivement appliqués au moment de l’exécution. Ils sont également entièrement compatibles avec l’héritage de classe, ce qui permet de réduire le risque d’erreurs dues à des annotations obsolètes ou incompatibles.

Syntaxe de base

La syntaxe du type d’intersection est similaire aux types d’union :

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

Dans cet exemple, $Union sera satisfait par toute valeur qui est Soit Countable ou alors Stringable. $Intersection n’acceptera que les valeurs qui correspondent tous les deux les contraintes. Vous obtiendrez un TypeError si vous affectez à la propriété une valeur qui implémente un ou zéro des types suggérés.

Les types d’intersection sont pris en charge partout où les indicateurs de type fonctionnent. Vous pouvez les utiliser avec des définitions de propriétés, des paramètres de fonction et des valeurs de retour.

Contrairement aux types union, les intersections ne peuvent que taper des interfaces et des classes. Une intersection scalaire comme int&string n’a pas de sens car il ne pourra jamais être satisfait. le mixed type est également interdit, car chaque valeur satisfera sa contrainte.

Écart de type

Les types d’intersection respectent les règles de variance existantes de PHP. Les types de retour des méthodes substituées doivent être covariants, tandis que les types de paramètres sont contravariants. Les propriétés de classe sont toujours invariantes, de sorte que les enfants ne peuvent pas modifier la définition de type à moins que la nouvelle signature ne soit à la fois un sous-type et un super-type de celui hérité.

Pour les valeurs de retour, les règles de variance signifient que vous pouvez ajouter des types d’intersection supplémentaires dans les méthodes remplacées. Les méthodes peuvent également supprimer, mais pas ajouter, des types aux intersections utilisées comme paramètres. Ces règles appliquent le principe de substitution de Liskov.

interface I1 {
    public function method1(A&B $demo) : X&Y;
    public function method2(A&B $demo) : X&Y;
}
 
interface I2 extends I1 {
 
    // ALLOWED
    public function method1(A $demo) : X&Y&Z;
 
    // NOT ALLOWED
    public function method2(A&B&C $demo) : X;
 
}

Dans le cas de method1, les contraintes n’ont pas réellement changé. Vous déclarez que la méthode surchargée peut en fait fonctionner avec n’importe quel A, même si ce n’est pas aussi un X. C’est moins spécifique, ce qui entraîne une variance de paramètre acceptable. La déclaration de retour est Suite spécifique, indiquant que la valeur mettra en œuvre X, Y et Z; dans ce scénario, l’ajout de spécificité ne rompt pas le contrat, car la valeur sera toujours acceptée par tout ce qui tape I1.

le method2 la dérogation est interrompue pour les deux chefs d’accusation. En exigeant que le paramètre d’entrée satisfasse A, B et C, ce n’est plus un remplacement I1. De même, method2 ne garantit que la valeur de retour sera une instance de X. Cela rompt le contrat comme quoi que ce soit de tapageur I1 exige que la valeur satisfasse l’intersection de X et Y.

Les intersections inversent les règles de variance pratique des types d’union. Comme les unions sont combinées à l’aide de « ou », les enfants peuvent ajouter des types de paramètres et supprimer des types de retour. Le principe de substitution de Liskov est satisfait lorsque l’effet d’élargissement et de rétrécissement des contraintes de type est inversé.

Comme pour les types d’union, les règles de variance s’appliquent également aux types qui composent une intersection – c’est l’individu X et Y parties de X&Y. Vous pouvez restreindre un type lorsque vous le retournez – en indiquant que vous retournerez une sous-classe – ou l’élargir en tant que paramètre, en acceptant une super-classe.

Les intersections possèdent également des règles spéciales concernant l’aliasing et les implémentations concrètes. Si vous tapez X&Y mais écrire une interface Z extends X, Y, c’est logique que Z satisfait la contrainte. Par conséquent, vous pouvez taper Z à la place de X&Y partout où la covariance est autorisée :

interface Test extends X, Y {}
 
interface Demo1 {
    public function demo() : X&Y;
}
 
interface Demo2 {
    public function demo() : Test;
}

Cela vous permet de taper une classe ou une interface concrète si vous dépendez de fonctionnalités supplémentaires. C’est acceptable tant que toutes les contraintes de l’intersection sont satisfaites par le dernier typehint.

Quand utiliser les types d’intersection ?

Les types d’intersection sont pour les moments où vous voulez être sûr qu’une valeur satisfait une interface composée sans réellement définir cette interface. Les versions précédentes de PHP ne fournissaient aucun support natif pour cela, vous deviez donc ajouter un gâchis de passe-partout supplémentaire à votre base de code :

interface CountableStringable extends Countable, Stringable {
    // ...
}
 
class FakeArray implements CountableStringable {
 
    public array $items = [];
 
    public function count() : int {
        return count($this -> items);
    }
 
    public function __toString() : string {
        return implode(", ", $this -> items);
    }
 
}
 
class DemoClass {
 
    public CountableStringable $Value;
 
}

Cela conduit à un excès d’interfaces peu profondes de type stub pour obtenir un comportement d’intersection de base. Bien que les développeurs PHP aient survécu sans intersections à ce jour, leur présence contribue à solidifier les capacités composées du système de typage. L’utilisation d’intersections natives crée un code plus propre et plus intuitif.

Qu’en est-il des types composites ?

Il n’est pas possible de combiner les types intersection et union dans le même typehint. Bien que cela soit techniquement possible, cela a été omis de la RFC actuelle car il existe des ambiguïtés autour de la syntaxe, de la priorité et de la variance.

Les types composites restent une idée pour l’avenir. S’ils étaient ajoutés, vous pourriez commencer à ajouter des astuces de type complexes comme celle-ci :

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

Cet exemple de classe combine les deux implémentations ci-dessus. Si cela fonctionnait, cela vous permettrait d’adopter des types d’intersection natifs tout en conservant une compatibilité descendante avec les anciennes classes en utilisant l’approche « fake ».

Des types composites à part entière compléteraient la gestion des types multiples facilitée par les unions et les intersections. En attendant, vous devrez continuer à écrire vos propres interfaces composites dans ces scénarios.

Résumé

Les types d’intersection arrivent dans PHP 8.1 et débloqueront des possibilités plus avancées au sein du système de types. L’extension des options autour des types composites réduit la quantité de code que vous devez écrire lorsque plusieurs interfaces sont prises en charge.

Les intersections sont une fonctionnalité facultative qui n’introduira aucune incompatibilité avec le code existant. La RFC a été implémentée dans la troisième version alpha de PHP 8.1. La version finale arrivera fin novembre plus tard cette année.

★★★★★