Wendell Adriel, ingénieur logiciel senior dans l’équipe Open Source de Laravel, a publié un brouillon de RFC intitulé « Typed array declarations » sur la liste de diffusion PHP internals. La proposition est disponible à https://wiki.php.net/rfc/typed_array_declarations et a été discutée dans un fil commencé le 16 juillet 2026.
La RFC permettrait aux développeurs de déclarer les types des valeurs d’un tableau et, en option, ceux des clés. La syntaxe `array<TValue>` représenterait un tableau à clés entières, tandis que `array<TKey, TValue>` serait utilisée lorsque le type de clé doit être explicite. Les déclarations `array` simples existantes resteraient inchangées.
Le brouillon définit trois niveaux d’implémentation qui partagent la même syntaxe et les mêmes métadonnées Reflection, mais diffèrent par l’application. Le niveau 1 reconnaît la déclaration lors de l’analyse et l’expose via Reflection, sans vérifier les éléments individuels. Le niveau 2 valide les clés et les valeurs quand un tableau franchit une limite déclarée, comme une assignation complète de propriété, un argument de fonction, une valeur de retour, une valeur par défaut ou une constante de classe typée ; les écritures directes par dimension, par exemple `$obj->prop['x'] = ...`, restent cependant acceptées. Le niveau 3 inclut le niveau 2 et applique la contrainte aux mutations et références ultérieures de la propriété, de sorte qu’une assignation complète et une écriture directe par dimension déclenchent toutes deux une `TypeError` avant que la valeur invalide ne soit stockée. Adriel recommande actuellement le niveau 3 pour les propriétés typées, car il préserve la garantie que la déclaration semble offrir. Aucune implémentation n’existe encore ; il a demandé des retours sur la sémantique d’exécution et le niveau approprié avant de commencer à coder.
Lazare Inepologlou a répondu en premier. Il a noté que, puisque la RFC limite les clés à `int` ou `string`, aucun sous-type n’est possible, donc une relation de sous-typage `K1 <: K2` ne peut jamais s’appliquer et seule l’égalité `K1 = K2` est possible. Il a aussi fait valoir que la covariance des valeurs n’est justifiée que pour les tableaux en lecture seule ; les opérations d’écriture placent le type valeur en position contravariante, ce qui rend un sous-typage covariant sain impossible sans séparer clairement les interfaces de lecture et d’écriture. Adriel a publié une v0.2 de la RFC intégrant ces remarques.
Rob Landers a ensuite soulevé des préoccupations plus générales. Selon lui, la proposition chevauche fortement la RFC sur les génériques réifiés, actuellement suspendue jusqu’après le gel de code en cours, avec une reprise des discussions espérée à la fin août ou début septembre au plus tôt. Les deux propositions doivent répondre aux mêmes questions sur les types paramétrés, la variance, Reflection, l’application à l’exécution, l’inférence et l’identité de type. Il a donc mis en garde contre l’engagement de règles spécifiques aux tableaux avant la discussion du design générique plus large, au risque de contraindre les génériques ou de aboutir à deux modèles de paramétrage incompatibles.
Landers a également critiqué le modèle de variance proposé. Pour une collection native mutable, la variance est généralement dangereuse à moins que l’API ne sépare clairement lecture et écriture. La RFC sur les génériques réifiés rend donc les paramètres génériques invariants par défaut et n’autorise la covariance ou la contravariance que là où leur sécurité est démontrable. Le brouillon sur les tableaux typés, en revanche, considère `array<Dog>` compatible avec `array<Animal>` uniquement à certaines frontières par valeur, en s’appuyant sur la séparation copy-on-write de PHP, puis redevient invariant pour les alias modifiables et ajoute des règles supplémentaires pour les références partagées. Landers a soutenu qu’il ne s’agit pas d’une relation de sous-type classique, mais d’une compatibilité de frontière dépendante du contexte, fondée sur le comportement interne des tableaux et des références. Cela serait difficile à comprendre pour les utilisateurs et difficile à appliquer de manière cohérente par le moteur. Il a proposé de rendre les tableaux paramétrés invariants, par exemple `array<int, Dog>` n’est pas un sous-type de `array<int, Animal>`, et d’offrir la covariance via une collection ou une interface en lecture seule si besoin.
Landers a aussi trouvé la syntaxe à un argument `array<TValue>` déroutante, car elle signifie implicitement `array<int, TValue>`. Ce n’est pas un tableau général de valeurs, car les clés de type string sont rejetées, mais ce n’est pas non plus une liste, car les clés entières n’ont pas besoin d’être contiguës ou de partir de zéro. Il s’attendrait à ce que `array<TValue>` ne contraigne que le type de valeur en laissant le type de clé comme `int|string`, et a suggéré un futur `list<TValue>` pour la forme plus restrictive à clés numériques.
Un dernier sujet de préoccupation était la validation répétée à l’exécution. Les tableaux PHP ordinaires ne conservent pas d’identité de type d’élément fiable, donc toute garantie de type est perdue lorsqu’un tableau traverse une frontière non typée. À chaque frontière typée suivante, PHP doit revalider l’ensemble du tableau de manière récursive. Pour les tableaux volumineux ou imbriqués, cela peut introduire un coût O(n) ou O(n) récursif à chaque appel. Landers a donc recommandé fortement d’attendre la RFC sur les génériques, ou à tout le moins de limiter cette RFC à des expérimentations sur la syntaxe et Reflection, sans adopter de sémantique de variance et d’exécution indépendante.
Adriel a répondu qu’il partageait ces préoccupations. Il identifie désormais deux voies possibles : implémenter seulement le niveau 1 dans cette RFC, ce qui serait assez simple pour PHP 8.7, et reporter les niveaux 2 et 3 dans une future RFC après la conception des génériques ; ou reporter l’ensemble de la RFC jusqu’après les génériques, puis viser le niveau 2 ou 3, le niveau 3 étant son objectif préféré. Il a précisé avoir publié une v0.2 et être satisfait de l’une ou l’autre approche.