Licence CC BY-NC-ND

Sortie de PHP 8

Publié :
Auteur :
Catégories :
Temps de lecture estimé : 9 minutes

Tous les ans, les développeurs de PHP travaillent d’arrache pied pour nous sortir une nouvelle version de PHP en fin d’année. Et à chaque fois c’est beaucoup de nouvelles fonctionnalités très intéressantes qui sont intégrées au langage. Découvrons ensemble les nouvelles fonctionnalités de cette nouvelle version majeure.

Une nouvelle année de PHP

Tous les ans les équipes de PHP nous préparent une nouvelle version de PHP. Depuis quelques années PHP arbore une version 7. Cette dernière a marqué une nouvelle ère de performances car elle a intégré PHP NG, une modification profonde de PHP.

Ce travail était à la base réalisé dans l’idée de changer la structure de PHP pour y intégrer du JIT (Just In Time). Mais le résultat a été si performant et le travail était encore si long pour arriver à une version JIT que les équipes ont décidé de la sortir quand même.

Mais qu’à cela ne tienne, le travail acharné paie: et PHP 8.0 est cette version qui nous amène le JIT, mais pas que ! La communauté a été très active sur PHP cette dernière année et beaucoup de nouvelles fonctionnalités sont arrivées en même temps.

Détaillons ensemble les nouvelles fonctionnalités majeures du langage.

Nouvelles fonctionnalités

Changements dans les casts de nombres

Commençons ce tour des nouveautés en douceur :) .

Lorsque vous passez une chaîne de caractères en paramètre d’une fonction qui attend un nombre, PHP tente de tout convertir en nombre. En PHP 7, si cette chaîne n’était pas convertible, la fonction recevait 0.

Avec PHP 8 si la chaîne de caractère est effectivement un nombre, elle est convertie, sinon vous obtiendrez une exception.

function foo(int $i) {

}

foo('2 et autre chose'); // throw TypeError
foo('2'); // fonctionne toujours si vous n'avez pas spécifié le strict types

Les unions de types

Clairement l’une des nouvelles fonctionnalités qui me plaît le plus ! Dans les dernières versions de PHP nous avons vu arriver le typage strict, mais lorsqu’on prend plusieurs types potentiels en paramètres il nous faut toujours re-vérifier le type car on ne peut pas réclamer cela à PHP. Dans cette nouvelle version de PHP on pourra donc faire des unions de type et s’éviter cette tâche.

Voici un exemple d’interface fonctionnant avec l’union de types :

interface ContainsNumberInterface
{
    public function setNumber(int|float $number);
    public function getNumber(): int|float;
}

Le type mixed

C’est un nouveau type qui vient s’ajouter aux types natifs existant dans PHP. Il a fait longtemps débat car d’un côté inutile, puisqu’il n’oblige à rien lors de l’utilisation d’une fonction ou d’un attribut. Mais PHP 8 rajoute ce type. Voyez là l’obligation de tout typer explicitement ;) .

class Something
{
    public mixed $userData;
}

Note: il a été décidé d’utiliser mixed et non pas any comme on peut voir dans d’autres langages car la communauté PHP entière s’accorde à utiliser ce wording pour spécifier un "multi-type" en documentation.

Les expressions match

Plus rapide à écrire, mais aussi plus rapide à exécuter qu’un switch, les expressions match ressemblent tout de même grandement à un switch :

  • Elles retournent directement quelque chose
  • Elles font une comparaison stricte contrairement au switch

En voici un exemple illustratif :

// En utilisant un switch
switch(8.0) {
  case "8.0":
    $result = "Oh non !";
    break;
  case 8.0:
    $result = "Ce que j'espère";
    break;
}
echo $result; // Affiche "Oh non !"

echo match (8.0) {
    "8.0" => "Oh non !",
    8.0 => "Ce que j'espère",
}; // Affiche "Ce que j'espère"

Les arguments nommés

Certaines fonctions ont une longue liste d’arguments optionnels, et devoir spécifier les arguments intermédiaires n’est pas toujours utile ou peut même porter à confusion ! PHP 8 nous propose donc cette nouvelle fonctionnalité : les arguments nommés.

Voici un exemple :

<?php
$items = [1, 2, 'foo'];
array_filter(array: $items, callback: function ($item) { return is_int($item); });

Les attributs

A partir de maintenant on s’accordera pour dire "propriété" de classe et "attribut" pour ce qui va suivre d’accord ? ;)

En PHP on a l’habitude d’avoir des commentaires contenant des annotations. Heureusement l’API de réflexion de PHP nous permet de simplifier le processus de parsing des annotations en commentaires… Mais ça n’était pas assez au goût général, et ça fait d’ailleurs depuis PHP 5.4 (environ) que les discussions sont ouvertes au sujet de faire quelque chose de "plus intégré à PHP". (pour les annotations Symfony et la plupart des frameworks utilisent un package nommé doctrine/annotations)

Nous y voici donc, on peut à présent utiliser les attributs pour remplacer les annotations. Voyons comment on peut déclarer un attribut.

#[Attribute]
class Column
{
    public string $name;

    public function __construct(string $name = null)
    {
        $this->name = $name;
    }
}

Voici un exemple d’utilisation de notre attribut. (Bientôt nos entités doctrine ressembleront à cela !)

final class User
{
    #[ORM\Id()]
    #[ORM\Column("id")]
    private int $id;
}

Et pour finir on utilise l’API de réflexion de PHP:

$reflectionClass = new ReflectionClass(User::class);
$attributes = $reflectionClass->getMethods()[0]->getAttributes(Column::class); // ✨

Note : Les attributs doivent être supportées par votre librairie, PHP ne fera pas la conversion automatiquement entre annotation et attributs.

Nouveautés sur le throw

Dans un premier temps, la clause throw est devenue une expression. C’est tout bête, mais ça permet par exemple de rendre le code suivant valide:

$value = $nullableValue ?? throw new InvalidArgumentException();

Et une petite modification a été faite sur le catch: le nom de variable est maintenant optionnel si vous n’avez pas besoin de cette dernière.

try {
    throw new TypeError();
} catch (TypeError) {
    echo 'oups erreur de type';
}

L’opérateur « Null Safe »

C’est l’une des fonctionnalités qui m’attire le plus: elle permet de sortir de ce qu’on appelle communément le « null hell ».

Concrètement, vous allez pouvoir remplacer ce code:

$country =  null;
 
if ($session !== null) {
    $user = $session->user;
 
    if ($user !== null) {
        $address = $user->getAddress();
 
        if ($address !== null) {
            $country = $address->country;
        }
    }
}

Par celui-ci:

$country = $session?->user?->getAddress()?->country;

N’oubliez cependant pas que moins vous aurez de null, mieux vous vous porterez psychologiquement !

Promotion des propriétés du constructeur

Cette fonctionnalité est en réalité une nouvelle façon de déclarer les propriétés de classe: PHP nous permet de les déclarer directement dans le constructeur, cela dans le but d’éviter le code redondant que l’on voit habituellement dans les classes.

Voici un exemple avant la nouvelle fonctionnalité :

class User
{
    private string $name;
    private string $email;

    public function __construct(string $name, string $email)
    {
        $this->name = $name;
        $this->email = $email;
    }
}

Et après :

class User
{
    public function __construct(
        private string $name,
        private string $email
    ) {}
}

Plutôt cool non ?

PHP 8 is JIT

PHP et le JIT, une longue histoire

En réalité ça fait plusieurs années que l’équipe de PHP, et plus particulièrement Dmitry Stogov qui s’est acharné à faire fonctionner PHP en JIT. Et ça n’a pas été sans problème. Le tout a été recodé plusieurs fois, l’une d’entre elles a d’ailleurs donné naissance à PHP 7 ! Si vous avez entendu parler de php ng, il s’agit en réalité d’une tentative de clean pour faire fonctionner PHP en JIT. Mais l’avancée a été telle qu’on a pu sortir une nouvelle version qui boost les perfs sans même passer en JIT.

Bref, nous y sommes. PHP 8 est JIT (Just In Time).

JIT, donc perf, n’est-ce pas ?

Et bien non. C’est une nouveauté qui a donné beaucoup de fil à retordre à l’équipe de PHP mais qui n’a qu’assez peu d’impact sur les performances de PHP au final. Par exemple si vous avez une API qui répond en 10ms, et bien il y a peu de chances que PHP8 vous aide: php a toujours été très optimisé pour cela, et PHP 7.4 avec le preloading a encore poussé la vitesse de chargement de PHP. Pas vraiment d’amélioration, mais PHP est déjà très rapide.

Là où vous aurez les meilleurs gains de performances c’est sur les process longs. Par exemple si vous voulez faire des traitements mathématiques, ou du machine learning. Bref, des processus longs. En voici d’ailleurs la preuve.

Démonstration des gains de performances sur des calculs mathématiques longs

Cependant, il faut reconnaître qu’il y a une légère amélioration de performances tout de même dans le cas général.

Fun fact

Le typage généralisé arrivé ces dernières années avait un coût en terme de perf, car ça ajoutait un check supplémentaire nécessaire. Alors qu’avec PHP 8 et JIT, c’est une optimisation.

Ne cherchez pas à typer pour la perf: c’est marginal. Mais c’est rigolo.


Une belle nouvelle version de PHP, malgré la petite taille de la core team de PHP, ces derniers nous sortent encore de belles nouvelles version, et c’est agréable !

Avant de vous laisser j’aimerais vous glisser un dernier mot : récemment nous avons également eu droit à une nouvelle version de composer. Le gestionnaire de paquet de PHP est à présent plus rapide, et il utilise moins de mémoire.

16 commentaires

Et bien non. C’est une nouveauté qui a donné beaucoup de fil à retordre à l’équipe de PHP mais qui n’a qu’assez peu d’impact sur les performances de PHP au final. Par exemple si vous avez une API qui répond en 10ms, et bien il y a peu de chances que PHP8 vous aide: php a toujours été très optimisé pour cela, et PHP 7.4 avec le preloading a encore poussé la vitesse de chargement de PHP. Pas vraiment d’amélioration, mais PHP est déjà très rapide.

Il y a quelques années, dans une ancienne boîte, j’ai eu pour mission de migrer une base de code de PHP5 à PHP7. Je me souviens encore à quel point j’ai été subjugué par les nouvelles performances ! Je suis un peu déçu, mais c’est sans grande surprise que j’apprends que le JIT n’est pas aussi époustouflant. C’est quand même très bien et j’espère que PHP pourra faire office de leader sur ce sujet, donnant peut-être une impulsion à d’autres grands langages (je pense à Python) pour suivre le pas.

Je ne pratique plus PHP depuis quelques temps déjà, mais je suis heureux d’apprendre qu’il évolue bien. Merci pour cet article.

+4 -0

Un truc que d’aucuns attendaient avec PHP 8.0 : les erreurs que PDO rencontre avec le serveur SQL sont désormais activées par défaut. Je n’ai cependant pas l’impression que l’équivalent ait été fait pour mysqli, dommage…

Evitez qu’on vous dise de les lire : FAQ PHP et SymfonyTutoriel WAMP • Cliquez 👍 pour dire merci Marquez vos sujets résolus

+0 -0
// En utilisant un switch
switch(8.0) {
  case "8.0":
    $result = "Oh non !";
    break;
  case 8.0:
    $result = "Ce que j'espère";
    break;
}
echo $result; // Affiche "Oh non !"

Je n’y connais pas grand chose en PHP, mais c’est pas censé afficher "Ce que j’espère" ? ^^

Édité par Tonio

+0 -0

@Tonio Justement non, le switch ne fait pas de vérification stricte (pas de comparaison de type), donc le premier case passe… on a donc bien "Oh non !" en sortie.

viki53

Ah oui c’est vrai (le fameux '===' ^^ ) … je comprend d’autant plus maintenant l’ajout de la fonctionnalité 'match' ! :)

+1 -0

En même temps mysqli n’a pas grand intérêt une fois que tu as PDO.

artragis

Certes. Je suis donc le seul à me demander pourquoi on active pour une interface et pas pour l’autre, même si l’argument de l’utilisation se tient ?

Evitez qu’on vous dise de les lire : FAQ PHP et SymfonyTutoriel WAMP • Cliquez 👍 pour dire merci Marquez vos sujets résolus

+0 -0

En même temps mysqli n’a pas grand intérêt une fois que tu as PDO.

artragis

Certes. Je suis donc le seul à me demander pourquoi on active pour une interface et pas pour l’autre, même si l’argument de l’utilisation se tient ?

Ymox

Il est tout à fait possible que ça soit pour des raisons de rétro-compatibilité. Cela-dit je n’ai pas les détails. Mais ça ne m’étonnerait pas que l’argument "ne pas casser wordpress" ait été choc dans le débat.

+1 -0

Il y a aussi le problème du fait que PDO n’a pas vraiment le même but et la même conception que MySQLi. MySQLi est vraiment fait pour s’intégrer dans un développement "proche" de MySQL et de ses API traditionnelle où l’erreur est une variable statique partagée (à la C donc). PDO est un vrai mapping objet qui va avoir un vrai workflow objet.

+0 -0

Il est tout à fait possible que ça soit pour des raisons de rétro-compatibilité. Cela-dit je n’ai pas les détails. Mais ça ne m’étonnerait pas que l’argument "ne pas casser wordpress" ait été choc dans le débat.

Nek

Il y a aussi le problème du fait que PDO n’a pas vraiment le même but et la même conception que MySQLi. MySQLi est vraiment fait pour s’intégrer dans un développement "proche" de MySQL et de ses API traditionnelle où l’erreur est une variable statique partagée (à la C donc). PDO est un vrai mapping objet qui va avoir un vrai workflow objet.

artragis

Je ne connais pas assez le code sous-jacent aux deux alternatives et ne connais pas non plus assez WordPress pour savoir que c’était mysqli qui était utilisé. Je pense cependant qu’il y a aussi des solutions existantes avec PDO pour lesquelles l’activation par défaut des messages d’erreur pourrait poser problème, j’imagine. La rétro-compatibilité, quand on passe à une version majeure, c’est plutôt attendu (sinon annoncé) qu’on ait des choses qui ne fonctionnent plus comme avant.

Si on finit par dire que c’est juste à cause de comment ("pas correctement")/par qui ("gros acteurs du web") chacune des APIs est utilisée, je persiste à trouver ça dommage.

Ils ont changé une valeur par défaut pour PDO, je pensais naïvement que c’était pas beaucoup plus compliqué pour mysqli.

Edit

Ah, alors en plus WordPress semble avoir besoin de GD qui n’est pas encore compatible PHP 8, l’argument « "ne pas casser wordpress" » ne tient pas vraiment  :D

Édité par Ymox

Evitez qu’on vous dise de les lire : FAQ PHP et SymfonyTutoriel WAMP • Cliquez 👍 pour dire merci Marquez vos sujets résolus

+0 -0

C’est un nouveau type qui vient s’ajouter aux types natifs existant dans PHP. Il a fait longtemps débat car d’un côté inutile, puisqu’il n’oblige à rien lors de l’utilisation d’une fonction ou d’un attribut. Mais PHP 8 rajoute ce type. Voyez là l’obligation de tout typer explicitement

Veux-tu dire qu’en PHP 8, le typage devient systématiquement obligatoire ? Ce qui signifierait du même coup une incompatibilité définitive avec du code PHP 5 ?

Ma plateforme avec 23 jeux de société classiques en 6 langues et 13000 joueurs: http://qcsalon.net/ | Apprenez à faire des sites web accessibles http://www.openweb.eu.org/

+0 -0

C’est un nouveau type qui vient s’ajouter aux types natifs existant dans PHP. Il a fait longtemps débat car d’un côté inutile, puisqu’il n’oblige à rien lors de l’utilisation d’une fonction ou d’un attribut. Mais PHP 8 rajoute ce type. Voyez là l’obligation de tout typer explicitement

Veux-tu dire qu’en PHP 8, le typage devient systématiquement obligatoire ? Ce qui signifierait du même coup une incompatibilité définitive avec du code PHP 5 ?

QuentinC

Aucune incompatibilité complète n’est au programme :) . Au contraire c’est un peu la marque de fabrique de PHP… Et en partie quelque chose qu’on lui repproche. L’idée de PHP++ (qui aurait cassé entièrement la compatibilité avec les très vieilles versions) a été lancée mais à part les créateurs de PHP (ironiquement), tout le monde a rejeté la l’idée en bloc.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte