PHP sort en version 8.2

Posté par  . Édité par Ellendhel, vmagnin, bobble bubble, Pierre Jarillon, Yves Bourguignon, Nils Ratusznik et palm123. Modéré par bobble bubble. Licence CC By‑SA.
Étiquettes :
20
5
déc.
2022
PHP

Après 3 Alpha, 3 Beta et 7 RC, et tout juste un an après la sortie de PHP 8.1, PHP, le langage de programmation pour le Web le plus connu et le plus utilisé, devrait être disponible après-demain en version 8.2, la sortie initiale prévue au 24 novembre ayant été reportée.
Petit tour (non-exhaustif) des nouveautés !

Sommaire

Nouvelles fonctionnalités

Classes en lecture seule (Readonly classes : RFC)

Après la possibilité offerte par PHP 8.1 d'ajouter le mot-clé readonly aux propriétés d'une classe, c'est désormais directement sur la classe que l'on peut le faire.
Cela permet d'alléger le code, en évitant la répétition du même mot-clé sur chacune des propriétés d'une classe (au risque de l'oublier sur l'une d'entre elles, notamment lorsque le code vient à évoluer), et de le rendre plus clair (quand la classe est readonly, toutes ses propriétés le sont forcément).
Cela permet aussi d'empêcher la création de propriétés dynamiques (propriétés non déclarées dans le corps de la classe).
Le principal usage est bien évidemment les classes DTO (Data Transfer Object), en permettant d'instancier des objets garantis immuables.

On est donc passé de ceci, en PHP 8.0 :

class Book 
{
    /**
     * Constructeur PHP utilisant la nouvelle syntaxe "Constructor property promotion" apparue avec PHP 8.0
     * @see https://stitcher.io/blog/new-in-php-8#constructor-property-promotion-rfc
     */
    public function __construct(
        private string $title,
        private string $author;
    )
    {}

    public function getTitle(): string 
    {
        return $this->title;
    }

    public function getAuthor(): string 
    {
        return $this->author;
    }
}

$book = new Book('A Game of Thrones', 'George R.R. Martin');
$book->getAuthor(); // "George R.R. Martin"

Puis ça, en PHP 8.1 :

class Book 
{
    /**
     * Les propriétés étant déclarées 'readonly', elles peuvent être déclarées 'public' sans risque.
     */
    public function __construct(
        public readonly string $title,
        public readonly string $author,
    )
    {}

    // Suppression des getters, devenus inutiles
}

$book = new Book('A Game of Thrones', 'George R.R. Martin');

// On peut désormais appeler directement la propriété, sans craindre de la modifier
echo $book->author; // "George R.R. Martin"
$book->author = 'J.R.R. Tolkien'; // Error: Cannot modify readonly property Book::$author

Pour arriver finalement à ceci, en PHP 8.2 :

// utilisation du mot-clé 'readonly' sur la classe directement
readonly class Book 
{
    /**
     * La classe étant déclarée 'readonly', les propriétés peuvent être déclarées 'public' sans risque,
     * sans pour autant avoir encore besoin de les déclarer 'readonly' une à une.
     */
    public function __construct(
        public string $title,
        public string $author,
    )
    {}

    // Suppression des getters, devenus inutiles
}

$book = new Book('A Game of Thrones', 'George R.R. Martin');
echo $book->author; // "George R.R. Martin"
$book->author = 'J.R.R. Tolkien'; // Error: Cannot modify readonly property Book::$author
$book->genre = 'Epic fantasy'; // Uncaught Error: Cannot create dynamic property Book::$genre

ATTENTION !
Un objet readonly n'est pas forcément immuable ! Si un objet A a une référence vers un objet B (composition), le fait que cette référence soit readonly garantit uniquement que A ne pointera jamais vers C à la place de B. Mais cela n'empêche pas pour autant les propriétés de B de pouvoir changer dans le temps (si elles ne sont pas elles-mêmes readonly, évidemment).

Dépréciation des propriétés dynamiques (Deprecate dynamic properties : RFC)

Dans la continuité du refus d'ajouter une propriété dynamique sur une classe readonly, une Deprecated est désormais levée lorsqu'on fait appel à une propriété inexistante au sein de la classe/de l'objet.
Ex :

class User {
    public $name;
}
$user = new User;

// Assigns declared property User::$name
$user->name = "foo";

// Oops, a typo:
$user->nane = "foo";
// PHP <= 8.1: Silently creates dynamic $user->nane property.
// PHP    8.2: "Deprecated: Creation of dynamic property User::$nane is deprecated"
// PHP    9.0: Throws Error exception.

Néanmoins, les cas où il faut pouvoir continuer à créer des propriétés dynamiques ont été pris en compte. Pour cela, 3 solutions :

Ajouter les méthodes magiques __get et/ou __set :
class Post
{
    private array $properties = [];

    public function __set(string $name, mixed $value): void
    {
        $this->properties[$name] = $value;
    }

    // …
}

// …

$post->name = 'Name'; // Pas de message de dépréciation
Utiliser la classe stdClass de PHP (ou en hériter) :
/*
 * Ne faites pas ça : ça marche mais c'est une solution fortement déconseillée !
 */
class Post extends stdClass
{
}

$post = new Post();

$post->name = 'Name'; // Pas de message de dépréciation
Ajouter l'attribut #[AllowDynamicProperties] à la classe :
/*
 * Solution la plus recommandée pour gérer le code legacy, car l'impact est nul.
 */
#[AllowDynamicProperties]
class Post
{
}

$post = new Post();

$post->name = 'Name'; // Pas de message de dépréciation

À terme (PHP 9), le message passera de Deprecated à la levée d'une exception de type Error.

Nouveaux types de retour : null, true, et false (Allow null and false as stand-alone types : RFC)

Il est désormais possible d'indiquer que le type de retour d'une fonction/méthode est null, true, ou false. C'est notamment utile pour les fonctions de PHP qui renvoient une valeur, ou false si un problème a été rencontré.
Par exemple :

/*
 * Trouve la première occurrence de $needle dans $haystack
 * @return la portion de la chaîne, ou false si needle n'est pas trouvé.
 */
strstr(string $haystack, string $needle, bool $before_needle = false): string|false

Masquage des données sensibles dans les logs (Redacting parameters in back traces : RFC)

Il est désormais possible d'indiquer que la valeur d'un paramètre ne doit jamais se retrouver dans des traces d'erreurs. C'est évidemment très utile pour éviter qu'un mot de passe ne finisse en clair dans un fichier de logs.
Pour cela, il faut ajouter un attribut à la variable concernée, comme ceci :

function test(
    $foo = null,
    #[\SensitiveParameter] $bar = null,
    $baz = null
) {
    throw new \Exception('Error');
}
test(baz: 'baz');
/*
Fatal error: Uncaught Exception: Error in test.php:8
Stack trace:
#0 test.php(11): test(NULL, Object(SensitiveParameterValue), 'baz')
#1 {main}
  thrown in test.php on line 8
*/

Comme on le voit dans la trace d'erreur, la valeur du paramètre en entrée $bar a été remplacée par Object(SensitiveParameterValue).

Constantes dans les Traits (RFC)

Il est désormais possible d'inclure des constantes au sein d'un Trait.
La syntaxe suivante est donc désormais valide :

trait T {
    public const CONSTANT = 42;

    public function doSomething(): void {
        // Fatal Error
        echo T::CONSTANT;

        // OK
        echo self::CONSTANT;
        echo static::CONSTANT;
        echo $this::CONSTANT;
    }
}

Retrait du support de libmysql (Remove support for libmysql from mysqli : RFC)

Le support de la bibliothèque libmysql a été retiré de PHP, pour ne conserver désormais que le support de mysqlnd. Si vous utilisez PHP avec MySQL (que ce soit avec l'extension PHP mysqli ou avec PDO_mysql), vous ne devriez même pas vous en rendre compte : mysqlnd est utilisée par défaut depuis… PHP 5.4 (sortie en 2012).

Liste complète des RFC

La liste complète des apports de cette nouvelle version est consultable ici.

PHP 8.3

La prochaine version sera la 8.3, prévue (pour l'instant) pour novembre 2023.
La liste des nouvelles fonctionnalités n'est évidemment pas encore arrêtée, mais on peut d'ores et déjà la retrouver ici.

  • # Trop tôt

    Posté par  . Évalué à 9.

    Euh… J'avais expressément indiqué dans le chapô qu'il fallait attendre le 08/12 !

    • [^] # Re: Trop tôt

      Posté par  (site web personnel, Mastodon) . Évalué à 5.

      Mais ça n'a pas été retiré, c'est bien dans le chapo :-)

      • [^] # Re: Trop tôt

        Posté par  . Évalué à 2.

        C'est de ma faute, je suis désolé ; je réalise que j'ai lu en diagonale le chapeau avant de me pencher sur la suite, puis j'ai soumis. Toutes mes excuses, je vois avec la modération comment faire :s

    • [^] # Re: Trop tôt

      Posté par  . Évalué à 6.

      Encore un truc publié avec un Ipot mal réglé.

      • [^] # Re: Trop tôt

        Posté par  (site web personnel, Mastodon) . Évalué à 3.

        C'est compliqué à paramétrer ces trucs aussi, faut dire (surtout avec des secondes intercalaires qui vont disparaître, un calendrier grégorien qui n'a pas été appliqué partout au même moment et des années qui commencent à des dates différentes selon les endroits).

        « Tak ne veut pas quʼon pense à lui, il veut quʼon pense », Terry Pratchett, Déraillé.

      • [^] # Re: Trop tôt

        Posté par  (site web personnel, Mastodon) . Évalué à 2.

        - avec un Ipot mal réglé
        + par une personne mal réveillée

        Ça arrive ; errare humanum est.

        “It is seldom that liberty of any kind is lost all at once.” ― David Hume

    • [^] # Re: Trop tôt

      Posté par  . Évalué à 5.

      • [^] # Re: Trop tôt

        Posté par  . Évalué à 3.

        Oui :)
        Encore désolé pour ce raté, et merci pour cette dépêche !

  • # Typo dans le premier bloc de code

    Posté par  (site web personnel, Mastodon) . Évalué à 1.

    Il y a une typo dans le premier bloc de code, private string $author; doit finir par une virgule : private string $author,.

    • [^] # Re: Typo dans le premier bloc de code

      Posté par  . Évalué à 1. Dernière modification le 06 décembre 2022 à 08:56.

      La fin de ligne devrait même être vide en fait.

          public function __construct(
              private string $title,
              private string $author
          )
          {}
      • [^] # Re: Typo dans le premier bloc de code

        Posté par  . Évalué à 4. Dernière modification le 06 décembre 2022 à 16:55.

        Alors on peut dire que tu n'as pas tort, et les 2 possibilités n'amènent ni erreur, ni warning.

        Cependant, ça m'insupporte grandement dans ces cas là d'avoir la dernière ligne sans virgule (autant dans les args d'une méthode ou dans un tableau écrit en multiligne).

        C'est tellement plus simple, en mettant des virgules à chaque ligne, de dupliquer n'importe laquelle pour aller plus vite, ou pour coller à la fin des lignes copiée d'une autre méthode/d'un autre tableau sans se retrouver avec la typo de virgule oubliée.

        J'ai du mal à comprendre pourquoi les développeurs continuent à ne pas la mettre à la fin.

      • [^] # Re: Typo dans le premier bloc de code

        Posté par  (site web personnel, Mastodon) . Évalué à 4.

        Pourrait et non devrait… Si tu mets la virgule ça marche aussi et perso je préfère parce-que quand tu rajoutes une ligne à la suite tu n'as pas besoin de te préoccuper des lignes d'avant (et de les toucher dans le diff)

        “It is seldom that liberty of any kind is lost all at once.” ― David Hume

        • [^] # Re: Typo dans le premier bloc de code

          Posté par  . Évalué à 4.

          Et garder une virgule pour le dernier élément quand le langage le permet, ça simplifie la vie quand on fait des merges. Ca évite de résoudre des conflits de merges triviaux qu'il faut alors résoudre à la main.

  • # Traduction de deprecated

    Posté par  . Évalué à 8.

    Attention, il ne faut pas confondre le verbe to deprecate avec le verbe to depreciate.
    Voir par exemple les traductions proposées par Larousse :
    to deprecate
    to depreciate

    C'est une erreur très fréquente chez les francophones !

    • [^] # Re: Traduction de deprecated

      Posté par  . Évalué à 3.

      Attention, il ne faut pas confondre le verbe to deprecate avec le verbe to depreciate.

      Alors pour le coup, j'ai appris un truc.

      J'ai toujours traduit deprecated par déprécié et dans la prochaine version majeure y'aura pu. Alors qu'en fait c'est plutôt : "rohhhh n'utilise plus ce truc que j'ai codé avec uc mais prend le nouveau truc instable actuelle que je vais sortir bientôt" :p

    • [^] # Re: Traduction de deprecated

      Posté par  . Évalué à 1.

      Je suis pas sûr de voir la différence sémantique claire entre déprécier et dénigrer (j'ai l'impression que le faux ami est plus compréhensible parce qu'il est plus un anglicisme qu'une traduction) mais je suis d'accord avec la référence des traduction classique, rendre obsolète est la meilleure traduction possible.

      https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll

  • # Petite coquille

    Posté par  . Évalué à 0.

    Salut,
    Il y a une petite coquille dans le code.

    // Oops, a typo:
    $user->nane = "foo";
    //manque un m 
    // donc $user->name  au lieu de $user->nane
    ``
    • [^] # Re: Petite coquille

      Posté par  . Évalué à 6.

      Ben non, justement !
      Cet exemple de code est là pour montrer que PHP <= 8.1 considère cette typo comme une propriété dynamique. Ce qui peut parfois être un casse-tête à décoder (parce qu'on ne pense pas immédiatement avoir fait une typo dans le nom d'une propriété).
      D'où les 3 lignes de commentaires juste après :

      // PHP <= 8.1: Silently creates dynamic $user->nane property.
      // PHP    8.2: "Deprecated: Creation of dynamic property User::$nane is deprecated"
      // PHP    9.0: Throws Error exception.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.