PHP 8.3 a été publié comme prévu le 23 novembre et contient de nombreuses nouvelles fonctionnalités et améliorations depuis le lancement de PHP 8.2. Même si elle est officiellement considérée comme une version mineure, certaines des modifications de la 8.3 peuvent avoir un impact direct sur votre travail avec PHP – peut-être en vous aidant à coder plus rapidement et avec moins de bogues.

Nous allons nous plonger dans les changements les plus importants – et parfois ceux pas si importants – de cette dernière version.

Nouvelles fonctionnalités et améliorations de PHP 8.3

Commençons par explorer les fonctionnalités de PHP 8.3 qui font les gros titres.

Constantes de classe typées

La possibilité de déclarer des types pour les propriétés des classes est disponible depuis PHP 7.4. Cependant, malgré les nombreuses améliorations apportées au typage en PHP au fil des ans, il n’a pas été étendu aux constantes – jusqu’à maintenant.

Les constantes de classe – et cela inclut également les constantes d’interface, de trait et d’enum – peuvent être typées en PHP 8.3, ce qui rend moins probable que les développeurs s’éloignent de l’intention derrière la déclaration initiale d’une constante.

Voici un exemple basique utilisant une interface :

// Legal:
interface ConstTest {
    // Declared type and value are both strings
    const string VERSION = "PHP 8.3";
}

// Illegal:
interface ConstTest {
    // Type and value mismatch in this initial declaration
    const float VERSION = "PHP 8.3";
}

La valeur réelle de ces constantes de classe typées est révélée lorsque vous travaillez dans des classes dérivées des déclarations de base. Alors qu’une classe enfant peut fréquemment assigner une nouvelle valeur à une constante, PHP 8.3 peut vous aider à éviter de changer accidentellement son type de sorte qu’il devienne incompatible avec la déclaration initiale :

class ConstTest {
    const string VERSION = "PHP 8.2";
}

class MyConstTest extends ConstTest {

    // Legal:
    // It's OK to change the value of VERSION here
    const string VERSION = "PHP 8.3";

    // Illegal:
    // Type must be declared if it was specified in the base class
    const VERSION = "PHP 8.3";

    // Illegal:
    // In this case, we can't change the type declared in the 
    // base class, even if the new type and its value are compatible.
    const float VERSION = 8.3;
}

Gardez à l’esprit que le type assigné à une constante de classe peut varier lors de la réduction de plusieurs types ou de l’utilisation d’un type compatible :

class ConstTest {
    const string|float VERSION = "PHP 8.2";
}

class MyConstTest extends ConstTest {

    // Legal:
    // Here, it's OK to narrow the type declaration to string or float
    const string VERSION = "PHP 8.3";
    const float VERSION = 8.3;

    // Legal:
    // Value could be an int, but it's compatible with float 
    const float VERSION = 8;

    // Illegal:
    // We can't widen the type options here to include int
    const string|float|int VERSION = 8;
}

Deux types pris en charge pour d’autres propriétés lors de la validation des valeurs de retour – void et never – ne sont pas pris en charge en tant que types de constantes de classe.

Une nouvelle fonction json_validate()

Lorsque vous travaillez avec des données encodées en JSON, il est intéressant de savoir si la charge utile est syntaxiquement valide avant d’essayer de faire quelque chose avec.

Dans les versions précédentes de PHP, les développeurs utilisaient la fonction json_decode() et vérifiaient les erreurs lorsque cette fonction essayait de transformer les données JSON en tableaux associatifs ou en objets. La nouvelle fonction json_validate() de PHP 8.3 vérifie les erreurs sans utiliser toute la mémoire nécessaire pour construire ces tableaux ou structures d’objets.

Ainsi, dans le passé, vous auriez pu valider une charge utile JSON de la manière suivante :

$obj = json_decode($maybeJSON);

if (json_last_error() === JSON_ERROR_NONE) {
    // Probably do something with $obj   
}

Si vous n’avez pas l’intention de faire quelque chose immédiatement avec $obj dans l’exemple ci-dessus, c’est beaucoup de ressources utilisées juste pour confirmer la validité de la charge utile JSON originale. En PHP 8.3, vous pouvez faire quelque chose comme cela et économiser de la mémoire :

if (json_validate($maybeJSON)) {
    // Do something with $maybeJSON   
}

Remarque : il n’est pas très judicieux d’utiliser json_validate(), puis d’exécuter immédiatement les données à travers json_decode(), en utilisant de toute façon les ressources mémoire de decode. Il est plus probable que vous utilisiez la nouvelle fonction pour valider le JSON avant de le stocker quelque part ou de le livrer en tant que réponse à une requête.

Clonage en profondeur des propriétés de readonly

La possibilité de déclarer des propriétés de classe individuelles comme readonly est apparue en PHP 8.1. PHP 8.2 a introduit la possibilité d’assigner cet attribut à une classe entière. Cependant, de nombreux développeurs pensaient que les contraintes imposées lorsqu’ils travaillaient avec des classes contenant de telles propriétés entravaient la programmation.

Un RFC pour modifier le comportement de readonly a fait deux propositions :

  1. Permettre aux classes qui ne sont pas readonly d’étendre les classes qui le sont
  2. Permettre aux propriétés readonly d’être réinitialisées lors du clonage

C’est la seconde proposition qui a été intégrée à PHP 8.3. La nouvelle approche permet aux instances d’une classe avec des propriétés readonly d’être réinitialisées dans la méthode magique __clone (y compris via des fonctions invoquées depuis __clone).

Cet exemple de code tiré de la RFC montre comment cela fonctionne :

class Foo {
    public function __construct(
        public readonly DateTime $bar,
        public readonly DateTime $baz
    ) {}
 
    public function __clone() {
        // $bar will get a new DateTime when clone is invoked
        $this->bar = clone $this->bar; 

        // And this function will be called
        $this->cloneBaz();
    }
 
    private function cloneBaz() {
       // This is legal when called from within __clone
        unset($this->baz); 
    }
}
 
$foo = new Foo(new DateTime(), new DateTime());
$foo2 = clone $foo;

Nouvel attribut #[\Override]

Lors de l’implémentation d’interfaces en PHP, les programmeurs fournissent des fonctionnalités détaillées pour les méthodes nommées dans ces interfaces. Lors de la création d’une instance d’une classe, les programmeurs peuvent remplacer une méthode parent en créant une version alternative avec le même nom et une signature compatible dans l’instance enfant.

L’un des problèmes est que les programmeurs peuvent penser qu’ ils implémentent une méthode d’interface ou qu’ils remplacent une méthode parentale alors que ce n’est pas le cas. Ils peuvent créer une chose entièrement distincte à cause d’une faute de frappe dans le nom de la méthode de la classe enfant ou parce que des méthodes ont été supprimées ou renommées dans le code parent.

PHP 8.3 introduit l’attribut #[\Override] pour aider les programmeurs à clarifier le fait qu’une méthode doit avoir une lignée dans le code.

Voici un exemple basique :

class A {
    protected function ovrTest(): void {}
}

// This will work because ovrTest() 
// can be found in the parent class
class B extends A {
    #[\Override]
    public function ovrTest(): void {}
}

// This will fail because ovrBest() 
// (probably a typo) is not in the parent
class C extends A {
    #[\Override]
    public function ovrBest(): void {}
}

Récupération dynamique des constantes de classe et des membres de l’Enum

Contrairement aux autres propriétés du code PHP, la récupération des constantes de classe et des membres de l’Enum avec des noms de variables est un peu compliquée. Avant PHP 8.3, vous pouviez utiliser la fonction constant() comme ceci :

class MyClass {
    public const THE_CONST = 9;
}

enum MyEnum int {
    case FirstMember = 9;
    case SecondMember = 9;
}

$constantName = 'THE_CONST';
$memberName = 'FirstMember';

echo constant('MyClass::' . $constantName);
echo constant('MyEnum::' . $memberName)->value;

Maintenant, en utilisant les mêmes définitions de classe et d’Enum, vous pouvez obtenir le même résultat avec la récupération dynamique des constantes de PHP 8.3, comme ceci :

$constantName = 'THE_CONST';
$memberName = 'FirstMember';

echo MyClass::{$constantName};
echo MyEnum::{$memberName}->value;

Nouvelle méthode getBytesFromString()

Avez-vous déjà voulu générer des chaînes de caractères aléatoires en utilisant une collection de caractères pré-approuvée ? Vous pouvez maintenant le faire facilement avec la méthode getBytesFromString() qui a été ajoutée à l’extension Random de PHP 8.3.

Cette nouvelle méthode est simple : vous lui passez une chaîne de caractères comme source et vous spécifiez le nombre de caractères que vous voulez utiliser. La méthode sélectionnera alors des octets de la chaîne au hasard jusqu’à ce qu’elle atteigne la longueur spécifiée.

Voici un exemple simple :

$rando = new Random\Randomizer();
$alpha = 'ABCDEFGHJKMNPQRSTVWXYZ';

$rando->getBytesFromString($alpha, 6); //  "MBXGWL"
$rando->getBytesFromString($alpha, 6); //  "LESPMG"
$rando->getBytesFromString($alpha, 6); //  "NVHWXC"

Il est possible que la longueur demandée de la sortie aléatoire contienne plus d’octets que la chaîne d’entrée :

$rando = new Random\Randomizer();
$nums = '123456';

$rando->getBytesFromString($nums, 10); //  "2526341615"

Avec une chaîne d’entrée composée de caractères uniques, chacun d’entre eux a une chance égale d’être sélectionné pour le résultat aléatoire. Cependant, les caractères peuvent être pondérés en apparaissant plus souvent que d’autres dans la chaîne d’entrée. Par exemple :

$rando = new Random\Randomizer();
$weighted = 'AAAAA12345';

$rando->getBytesFromString($weighted, 5); //  "1AA53"
$rando->getBytesFromString($weighted, 10); //  "42A5A1AA3A"

Nouvelles méthodes getFloat() et nextFloat()

En complément de l’extension Random, PHP 8.3 introduit deux nouvelles méthodes pour générer des valeurs flottantes aléatoires : getFloat() et nextFloat().

Voici un exemple :

$rando = new Random\Randomizer();

// Generate a float value between a minimum 
//  value of 0 and a maximum value of 5
$rando->getFloat(0,5); // 2.3937446906217

La méthode getFloat() accepte également un troisième paramètre après les valeurs minimum et maximum. En utilisant un Enum Random\IntervalBoundary, il est possible de déterminer si les valeurs min et max peuvent être renvoyées par la fonction.

Voici les règles :

  • IntervalBoundary::ClosedOpen : la valeur min peut être renvoyée, mais pas la valeur max
  • IntervalBoundary::ClosedClosed : les valeurs min et max peuvent être renvoyées
  • IntervalBoundary::OpenClosed : min ne peut pas être retourné, max peut l’être
  • IntervalBoundary::OpenOpen : ni min ni max ne peuvent être renvoyés

Lorsque vous utilisez getFloat() sans spécifier l’Enum comme troisième paramètre, la valeur par défaut est IntervalBoundary::ClosedOpen.

Un exemple utile fourni par la documentation de la nouvelle fonction génère des coordonnées aléatoires de longitude et de latitude, où les latitudes peuvent inclure -90 et 90, mais où la longitude ne peut pas inclure -180 et 180 (puisqu’elles sont identiques) :

$rando = new Random\Randomizer();

printf(
    "Lat: %+.6f Long: %+.6f",
    $rando->getFloat(-90, 90, \Random\IntervalBoundary::ClosedClosed),

    // -180 will not be used 
    $rando->getFloat(-180, 180, \Random\IntervalBoundary::OpenClosed),
);

La nouvelle méthode nextFloat() revient essentiellement à utiliser getFloat() pour demander une valeur aléatoire comprise entre 0 et moins de 1 :

$rando = new Random\Randomizer();

$rando->nextFloat(); // 0.3767414902847

Autres changements mineurs dans PHP 8.3

PHP 8.3 inclut également un certain nombre de nouvelles fonctions et de changements mineurs. Nous les mentionnons ci-dessous avec des liens vers des ressources additionnelles (quand elles sont disponibles) :

Dépréciations dans PHP 8.3

Avec chaque nouvelle version de PHP, certaines fonctions et paramètres sont marqués pour une éventuelle suppression. Une fois dépréciées, ces fonctions ne sont pas recommandées pour une utilisation continue et génèrent des notifications dans de nombreux journaux lorsqu’elles apparaissent dans le code d’exécution.

Voici une liste des dépréciations en PHP 8.3, avec des liens vers des informations complémentaires :

Résumé

Nous avons examiné les changements significatifs apportés à PHP 8.3. Pour une liste granulaire de toutes les mises à jour de cette version, vous pouvez consulter le journal des modifications officiel de la version. Si vous prévoyez de déplacer votre code vers une plateforme utilisant la dernière version de PHP, le guide de migration 8.2-to-8.3 peut vous aider à éviter les problèmes.

Si c’est votre rôle d’installer PHP sur vos serveurs de développement ou de production, la version 8.3 est prête à être téléchargée.

Si vous êtes un client de Kinsta, vous pouvez compter sur nous pour rendre cette version disponible sur les serveurs de vos projets d’hébergement WordPress ou d’hébergement d’applications.

Steve Bonisteel Kinsta

Steve Bonisteel is a Technical Editor at Kinsta who began his writing career as a print journalist, chasing ambulances and fire trucks. He has been covering Internet-related technology since the late 1990s.