Quelques mois après la sortie de la très attendue version 8, voici que PHP 8.1 pointe déjà le bout de son nez.
Cette version sortira officiellement le 25 novembre prochain. Dans cet article, nous allons faire le tour des principales nouveautés, améliorations, changement et dépréciations de PHP 8.1.
Les énumérations
Les enums seront (enfin) disponibles dans PHP 8.1 ! Dire que cet ajout était attendu est un euphémisme.
Cet ajout va améliorer grandement PHP, et nous sommes particulièrement impatients de pouvoir l’utiliser chez Ldiro Softwares Inc.
Voici un petit exemple pour vous présenter ce que sont les enums, se basant sur les couleurs des jeux de cartes :
enum Suit
{
case Hearts;
case Diamonds;
case Clubs;
case Spades;
}
Et voici comment s’en servir :
class Card
{
public function construct(
private Suit $suit = Suit::Hearts
){}
public function setSuit(Suit $suit): void
{
$this->suit = $suit;
}
}
// utilisation
$card = new Card();
$card->setSuit(Suit::Clubs);
Comme vous pouvez le voir, les enums sont des types de données définis par l’utilisateur. Leur utilisation est assez familière, car elle se fait de la même manière que les classes et les objets.
Les enums peuvent posséder des méthodes, des méthodes statiques, implémenter des interfaces… L’ajout des enums à PHP 8.1 ouvre beaucoup de possibilité, et nous y reviendrons dans un article dédié.
Vous pouvez en apprendre plus en lisant notre article entièrement consacré aux énumérations.
Utilisation du mot clé "new" pour l'initialisation
Lorsque l’on souhaite donner une valeur par défaut à un attribut ou un argument d’une fonction, nous pouvons uniquement utiliser des types primitifs (string, int etc…). Si nous souhaitons utiliser des objets par exemple, nous devons le faire comme ceci :
class User
{
private string $name = 'John';
private DateTime $createdAt;
public function __construct()
{
$this->createdAt = new DateTime();
}
}
PHP 8.1 permet désormais d’utiliser le mot clé new dans nos initialisation, l’exemple précédent pourra dorénavant être écrit de la manière suivante :
class User
{
public function __construct(
private string $name = 'John',
private DateTime $createdAt = new DateTime()
){}
}
Propriétés readonly
Parmis les nouveautés de PHP 8.1, les propriétés de classes peuvent être définis en readonly. Cela signifie qu’elles ne pourront être écrite une seule fois, au moment de l’initialisation.
class User
{
public function __construct(
public readonly string $firstname
){}
}
Vous pourrez bien évidement accéder à ces attributs, mais une erreur sera levée si vous essayez de les modifier :
$user = new User('John');
echo $user->firstname; // Affiche "John"
$user->firstname = 'Jack'; // Erreur
Fiber
Majoritairement, le code PHP est ce que l’on appelle synchrone. C’est-à-dire que l’exécution du code s’arrête jusqu’à ce que le résultat soit renvoyé. Cette particularité peut ralentir l’exécution du code.
Bien qu’il existe des solutions tierces pour paralléliser l’exécution du code, il n’existe pas de solutions standards fournies par PHP.
Les fibers sont la façon dont PHP gère le parallélisme via les threads virtuels (ou threads verts). Cela va permettre aux fonctions PHP de s’interrompre sans arrêter tout le script.
Voici l’exemple donné par PHP dans la RFC :
$fiber = new Fiber(function (): void {
$value = Fiber::suspend('fiber');
echo "Value used to resume fiber: ", $value, "\n";
});
$value = $fiber->start();
echo "Value from fiber suspending: ", $value, "\n";
$fiber->resume('test');
Cette nouvelle API comporte de nombreux avantages en terme notamment de performance. Cela dit, la plupart des développeurs PHP ne l’utilisera probablement jamais.
En effet, les fibers sont une fonctionnalité avancée que la plupart des utilisateurs n’utiliseront pas directement. Cette fonctionnalité s’adresse principalement aux auteurs de bibliothèques et de frameworks. Il sera intéressant de voir comment ils implémentent Fibers dans leur écosystème.
Type never
Le type never permet d’indiquer que la fonction va arrêter l’exécution du programme. Que ce soit via la fonction exit, en lançant une exception ou autre. La documentation utilise l’exemple des fonctions de redirection avec la fonction exit :
function redirect(string $uri): never
{
header('Location : ' . $uri) ;
exit() ;
}
Les fonctions qui utilisent le type de retour never doivent satisfaire plusieurs conditions : ne pas utiliser le mot clé return explicitement ou implicitement, et terminer l’exécution par la fonction exit explicitement ou implicitement.
Bien que proche du type de retour void, il est différent car le type void permet de continuer l’exécution de l’application, ce qui n’est pas le cas du type never.
Utilisez le type void si vous souhaitez que l’application puisse continuer à s’exécuter. Sinon, le type never pourra être utilisé.
Nouvelle fonction array_is_list
PHP 8.1 introduit la nouvelle fonction array_is_list. Cette dernière va permettre de déterminer si le tableau est une liste, c’est à dire si les clés d’un tableau sont numériques, consécutives et sans “trou” dans la séquence :
array_is_list([]); // true
array_is_list(['apple', 2, 3]); // true
array_is_list([0 => 'apple', 'orange']); // true
// Le tableau ne commence pas à 0
array_is_list([1 => 'apple', 'orange']); // false
// Les clé sne sont pas dans l'ordre
array_is_list([1 => 'apple', 0 => 'orange']); // false
// Clés non numériques
array_is_list([0 => 'apple', 'foo' => 'bar']); // false
// Clés non consécutives
array_is_list([0 => 'apple', 2 => 'bar']); // false
Amélioration des performances
Des améliorations ont été apportées à opcache et notamment un important : Inheritance Cache.
Grâce a l’Inheritance Cache, toutes les classes dépendantes uniques (parent, interfaces, traits, etc..) sont reliées et les résultats sont stockés dans la mémoire partagée d’opcache.
D’après l’auteur de cette amélioration, Dimitry Stogov, les performances seraient améliorées de l’ordre de 5% à 8% !
Types d’intersection purs
PHP 8.1 ajoute la prise en charge des types d’intersection. C’est similaire aux types d’union introduits dans PHP 8.0, mais leur utilisation prévue est exactement l’inverse.
Alors que les types union exigent que l’entrée soit l’un des types donnés, les types d’intersection exigent que l’entrée soit de tous les types spécifiés. Les types d’intersection sont particulièrement utiles lorsque vous travaillez avec de nombreuses interfaces :
classe A {
private Traversable&Countable $countableIterator;
public function setIterator(Traversable&Countable $countableIterator) : void {
$this->countableIterator = $countableIterator;
}
public function getIterator() : Traversable&Countable {
retourne $this->countableIterator;
}
}
Constantes de classes finales
Traditionnellement, les constantes de classes peuvent être réécrite durant l’héritage. A partir de PHP 8.1, nous pouvons déclarer les constantes comme étant finales, pour éviter ce comportement :
class A {
final public const FOO = "Foo";
}
class B extends A {
public const FOO = "bar"; // Affiche "Fatal error: B::FOO cannot override final constant A::FOO"
}
Nouvelles fonctions fsync et fdatasync
PHP 8.1 ajoute les fonctions fsync et fdatasync pour forcer la synchronisation des changements de fichiers sur le disque et s’assurer que les tampons d’écriture du système d’exploitation ont été vidés avant de faire le return. Elles sembleront familières à ceux qui sont habitués aux fonctions Linux du même nom. C’est parce qu’elles sont apparentées, simplement implémentés pour PHP.
$file = 'test.txt';
$file = fopen('test.txt', 'w');
fwrite($file, 'content');
fsync($file);
fclose($file);
L’ajout de l’appel fsync() à la fin garantit que toutes les données contenues dans le tampon interne de PHP ou du système d’exploitation sont écrites dans le stockage. Toutes les autres exécutions de code sont bloquées jusqu’à ce moment-là.
La synchronisation des disques étant une opération du système de fichiers, la fonction fsync() ne fonctionnera que sur les flux de fichiers ordinaires. Les tentatives de synchronisation de flux autres que des fichiers émettront un avertissement.
La fonction fadatasync() est utile pour synchroniser les données mais pas nécessairement les métadonnées. Pour les données dont les métadonnées ne sont pas essentielles, cet appel de fonction rend le processus d’écriture un peu plus rapide.
Sous Windows, PHP 8.1 ne prend pas encore en charge fdatasync(). La fonction agit simplement comme un alias de fsync() sur le système de Microsoft.
Dépréciations de PHP 8.1
Bien que PHP 8.1 soit une version mineure, elle introduit quelques changements qui cassent la compatibilité avec les versions précédentes, ainsi que des dépréciations. Faisons un petit tour rapide de quelques-uns de ces changements.
Restriction de l'utilisation de $GLOBALS
Un petit changement dans la façon dont la super-variable $GLOBALS est utilisée aura un impact significatif sur les performances de toutes les opérations sur les tableaux.
Ce changement signifie que certains cas d’utilisation ne sont plus possibles avec $GLOBALS. Dans la RFC, les développeurs expliquent : “Ce qui n’est plus supporté, ce sont les modifications direct du tableau $GLOBALS. Tout ce qui suit générera une erreur de compilation” :
$GLOBALS = [];
$GLOBALS += [];
$GLOBALS =& $x;
$x =& $GLOBALS;
unset($GLOBALS);
De plus, le fait de passer la variable $GLOBALS par référence générera une erreur d’exécution.
L’impact devrait être globalement faible. un développeur a analysé les 2000 premiers paquets sur Packagist, et n’a trouvé que 23 cas qui seront affectés par ce changement. Ce qui explique pourquoi il a été décidé de l’ajouter dans PHP 8.1.
Ce changement pourrait être néanmoins conséquent, étant donné l’impact positif sur les performances qu’il aura partout dans notre code.
Dépréciation du passage de la valeur null aux arguments non-nullables des fonctions internes
Ce changement est assez simple : dans PHP 8.0, les fonctions internes acceptent actuellement null pour les arguments qui sont non-nullables. PHP 8.1 déprécie ce comportement. Par exemple, ceci est actuellement possible :
str_contains("string", null); // Renvoie true
Cela fonctionne actuellement car le second argument est converti en une chaine de caractère vide.
Dans la version PHP 8.1, ce type d’erreur génère un avertissement de dépréciation. Dans la version PHP 9, il sera converti en erreur de type.
Dépréciation de l'autovivification sur false
PHP permet nativement l’autovivification (auto-création de tableaux à partir de valeurs fausses). Cette fonctionnalité est très utile et utilisée dans de nombreux projets PHP, surtout si la variable est indéfinie.
Cependant, il existe une petite “bizarrerie” qui permet de créer un tableau à partir d’une valeur fausse et nulle.
Cela ne sera plus le cas dans PHP 8.1 :
$array = false;
$array[] = 2; // Affiche "Automatic conversion of false to array is deprecated"
Autres changements et dépréciations
Comme d’habitude avec chaque version, il y a beaucoup de changements très mineurs. Toutes sont répertoriées dans le guide UPGRADING sur GitHub et dans la RFC de dépréciation.
C’est terminé pour le tour des changements les plus importants concernant PHP 8.1. Gardez bien à l’esprit que la liste des nouveautés pourraient s’agrandir au cours de l’année, nous ne manquerons pas de mettre l’article à jour avec les dernières nouveautés de PHP 8.1.