Code

Les nouveautés PHP 8.1, fonctionnalités et améliorations

Retour au blog

La version PHP 8.1 est sortie le 25 novembre 2021. Profitons-en pour faire un tour d’horizon des principales nouveautés au programme de cette version.


Nous allons ici nous concentrer sur les principales nouveautés annoncées. Chaque sortie contient également son lot de dépréciations, de breaking changes et de modifications mineures, mais ces changements dépassent la portée de cet article. Si vous êtes intéressés, vous pouvez retrouver l'ensemble des changements liés à la version 8.1 de PHP sur le guide officiel de migration.

Types d’intersection purs

Le support pour les types d’intersection arrive en complément des types d’union introduits dans PHP 8.0, avec un usage qui se veut l’opposé. Là où les types d’union, déclarés à l’aide de l’opérateur | (OR), exigent qu’un paramètre soit d’un type parmi les types spécifiés, les types d’intersections, déclarés à l’aide de l’opérateur & (AND), exigent qu’un paramètre soit de tous les types spécifiés.

// Union type

public function foo(Foo|Bar $input); // $input must either be Foo or Bar

// Intersection type

public function foo(Foo&Bar $input); // $input must be Foo and Bar

Vous pouvez en apprendre plus sur les types d'intersection en vous rendant sur la page officielle.

Type de retour never

Le type de retour never indique qu’une méthode va interrompre le déroulement du programme (interruption provoquée soit par la levée d’une exception, soit par un appel à exit).

function dumpAndDie($value) : never {
	var_dump($value);
	exit() ;
}

La documentation de cette fonctionnalité est à retrouver ici.

Énumérations

Déjà présentes dans de nombreux langages, PHP 8.1 ajoute enfin le support des énumérations. Petit rappel : une énumération permet de définir un type avec un nombre fixe de valeurs possibles.

Prenons l’exemple d’un jeu de cartes. Les enseignes des cartes peuvent être définies dans une énumération.

enum Suit {
    case CLUBS;
    case DIAMONDS;
    case HEARTS;
    case SPADES;
}

Prenons maintenant un objet Card qui doit être initialisé avec un paramètre d'enseigne. Grâce à notre énumération, nous allons pouvoir fixer le type du paramètre attendu.

class Card
{
	public function __construct(Suit $suit){// code};
}


$card = new Card(Suit::CLUBS);

Les fonctionnalités liées aux énumérations sont nombreuses. En voici quelques-unes :

comme les classes, les énumérations peuvent définir des méthodes. Il est également possible de définir des méthodes statiques.

// Enumération et méthode

enum Suit {
    case CLUBS;
    case DIAMONDS;
    case HEARTS;
    case SPADES;

		public function getColor(): string
		{
			return match($this)
			{
				self::CLUBS => 'black',
				self::DIAMONDS => 'red',
				self::HEARTS => 'red',
				self::SPADES => 'black',
			};
		}
}

// Voici comment utiliser cette méthode
$suit = Suit::SPADES;
$suit->getColor(); // 'black'

comme les classes, les énumérations peuvent implémenter des interfaces.

il est possible d'assigner une valeur spécifique à chaque valeur d'énumération (uniquement de type int ou string). Dans ce cas, on parle de Backed enums.

enum Suit: string {
    case CLUBS = '♣️';
    case DIAMONDS = '♦️';
    case HEARTS = '♥︎';
    case SPADES = '♠️';
}

// récupérer la valeur associée
$value = Suit::DIAMONDS->value; // '♦️', value est une propriété publique readonly
// restorer depuis une valeur
$suit = Suit::from('♠️'); // Suit::SPADES

Pour un aperçu complet de toutes les fonctionnalités liées aux énumérations, vous pouvez consulter la page officielle de la RFC.

Fibers

Fibers (aka 'green threads' aka 'coroutines') est une nouvelle fonctionnalité de PHP pour gérer le parallélisme. En résumé, une Fiber est un bloc de code qui maintient sa propre stack (variables et état) et qui peut être démarré, suspendu ou arrêté soit par le code principal, soit par la Fiber elle-même.

Cette fonctionnalité n'est probablement pas amenée à être utilisée régulièrement dans votre code, mais vous pouvez retrouver les spécifications détaillées sur la page officielle de la RFC.

Améliorations des performances

Ce n'est pas une fonctionnalité en tant que telle, mais l'équipe de développement PHP a apporté des améliorations à opcache sous le nom "inheritance cache". Cela permet de mettre en cache les liens entre les différentes classes. Un gain d'amélioration de 5% à 8% a été constaté grâce à ce changement.

Vous pouvez retrouver plus de détails sur l'implémentation de ce changement sur la page github de la pull request.

Array unpacking avec les clés de type string

Le support pour array unpacking a été ajouté dans la version php 7.4 mais uniquement pour les clés numériques. Dans la version 8.1, il sera désormais possible d'utiliser l'array unpacking avec les clés de type string. Les règles de gestion en cas de clés avec une même valeur sont les mêmes que pour la fonction array_merge, à savoir que les clés déclarées en dernier vont écraser les précédentes.

$array1 = ["key1" => 1];
$array2 = ["key2" => 2];
$array = ["key1" => 0, ...$array1, ...$array2];

var_dump($array); // ["key1" => 1, "key2" => 2]

Lien vers la RFC de cette nouveauté, c'est ici.

Extension de l'utilisation du mot-clé new

L'usage du mot-clé new est étendu. Le code ci-dessous détaille les expressions qui sont désormais autorisées.

// initialisation de variable statique
static $x = new Foo;
 
// initialisation de constante de classe 
const C = new Foo;

// valeur par défaut de paramètre
function test($param = new Foo) {}
 
// argument d'Attributs
#[Attr(new Foo)]
class Test {
    public function __construct(
        public $prop = new Foo,
    ) {}
}

Les propriétés en lecture seule (Readonly properties)

Les propriétés de classe peuvent désormais être définies en lecture seule, empêchant donc une modification après leur initialisation.

class Person {
	public function __construct(
		public readonly $name
	) {}
}

$person = new Person('John');
$person->name = 'Jack' // cela va entraîner une erreur
// Error: Cannot modify readonly property Person::$name

Les détails de cette fonctionnalité sont à retrouver dans la RFC correspondante.

First-class callable syntax

Avec PHP 8.1, il sera possible de déclarer une closure depuis une fonction de rappel en appelant cette fonction de rappel avec l'argument ...

Un exemple de code sera sûrement plus parlant :

// notre fonction de rappel
function add($a,$b){return $a + $b;}

// déclaration de la closure
$fn = add(...)

// utilisation de la closure
echo $fn(a: 3, b: 4) // 7

Et toujours le lien vers la RFC de cette nouveauté, c'est ici.

Nouvelle méthode array_is_list

Cette nouvelle méthode va permettre de déterminer si les clés d'un tableau sont des clés numériques, dans l'ordre croissant, démarrant de l'indice 0. Finalement !

$list = [1 => 'a', 0 => 'b'];
array_is_list($list); // false car les clés ne sont pas ordonnées

$list = [0 => 'a', 1 => 'b'];
array_is_list($list); // true car les 3 conditions sont respectées

$list = ['a', 'b'];
array_is_list($list); // true car les 3 conditions sont respectées

$list = [1 => 'a', 2 => 'b', 3 => 'c'];
array_is_list($list); // false car le 1er indice ne commence pas à 0

Toutes les informations sont à retrouver sur cette page.

Constantes de classe final

Jusque là, les constantes de classe pouvaient être écrasées dans un contexte d'héritage. Avec la version 8.1 de PHP, il est désormais possible d'empêcher ce comportement en déclarant la constante avec le mot clé final. Voici un exemple de code illustrant cette fonctionnalité:

class Foo
{
    final public const X = "foo";
}
 
class Bar extends Foo
{
    public const X = "bar";
}
 
// Fatal error: Bar::X cannot override final constant Foo::X

Et pour en savoir plus, ça se passe ici.

Nouvelles fonctions fsync et fdatasync

fsync et fdatasync sont deux nouvelles fonctions permettant de s'assurer de la synchronisation des données du buffer vers le support physique de stockage. En d'autres termes, cela permet de s'assurer qu'une opération d'écriture est complète et que les données sont persistées.

Il faut noter que si l'argument passé à fsync ou fdatasync n'est pas un pointeur sur un fichier, un avertissement sera émis.

$fp = fopen('file.txt', 'w');
fwrite($fp, 'Hello world');

if (fsync($fp)) {
    echo "Synchronisation sur le disque effectuée avec succès";
}

Le lien vers la RFC de cette nouvelle fonctionnalité, est ici.

Notation de numération octale (Explicit octal integer literal notation)

Pour spécifier un nombre en notation octale, il est maintenant possible d'utiliser les préfixes 0o(zéro-o minuscule) and 0O (zéro-o majuscule) en plus du simple préfixe 0 (zéro).

0o16 === 14; // true
0o123 === 83; // true
 
0O16 === 14; // true
0O123 === 83; // true
 
016 === 0o16; // true
016 === 0O16; // true

Tous les détails de cette proposition sont à retrouver ici.

Comme on peut le voir, PHP en version 8.1 apporte son lot de nouveautés. Assurez vous d'avoir bien testé vos projets avant d'utiliser cette version en production.

Auteur

Publié le 09 décembre 2021

Ingénieur Logiciel · Web