Migration de code vers PHP 8 (partie 1)

Par @jbnahan69

Pourquoi migrer sur PHP 8 ?

Depuis le 28 novembre 2022, plus aucune version de PHP 7 et inférieur ne reçoit de patch de mise à jour. Le risque de faille de sécurité augmente avec le temps.

Outre, l'argument de la sécurité, PHP 8 apporte de nombreuses améliorations dans le code et en performance. Parlons dès maintenant des nouveautées.

Quelques nouveautés de PHP 8 (cœur)

La future version de PHP est encore en cours de développement (sortie prévue pour décembre 2020) mais la liste des nouveautés déjà réalisées est déjà accessible. Elle n'est cependant pas encore figée.

Vous avez surement entendu parler du JIT (Just in time) de PHP 8 mais cela changera-t-il quelque chose à notre quotidien ? Pour certains oui.

Pour la plupart des développeurs, une version majeure implique une migration du code. Dans le cas de l'évolution de notre code à quoi faut-il s'attendre ?

Articles de la série :

Partie 1 : Migration de code vers PHP 8 (partie 1)
Partie 2 : Migration de code vers PHP 8 MBString (partie 2)
Partie 3 : Nouvelle erreur ValueError dans PHP 8 (partie 3)

Les avertissements et avis ont été revus

Dans ce nombreux cas PHP remontait un avertissement ou un avis, nombreux sont ceux qui ont été transformés en erreur.

Un certain nombre d'avertissements ont été convertis en exceptions d'erreur :

  • Tentative d'écriture dans une propriété d'une variable qui n'est pas un objet. Auparavant, cette action crée implicitement un objet stdClass pour les chaînes nulles, fausses et vides.
  • Tentative d'ajout d'un élément dans un tableau pour lequel la clé PHP_INT_MAX est déjà utilisée.
  • Tentative d'utilisation d'un type non valide (tableau ou objet) comme clé de tableau ou décalage de chaîne.
  • Tentative d'écriture dans un index de tableau d'une valeur scalaire.
  • Tentative d'utilisation de la fonction unpack sur une variable qui n'est pas un tableau ou un Traversable.
  • Une erreur d'héritage due à une signature de méthode incompatible génèrera une erreur fatale à la place d'un avertissement PHP RFC : Always generate fatal error for incompatible method signatures.

Un certain nombre d'avis ont été convertis en avertissements :

  • Tentative de lecture d'une variable non définie.
  • Tentative de lecture d'une propriété non définie.
  • Tentative de lecture d'une propriété d'une variable qui n'est pas un objet.
  • Tentative d'accès à un index de tableau d'un non-tableau.
  • Tentative de conversion d'un tableau en chaîne.
  • Tentative d'utilisation d'une ressource comme clé de tableau.
  • Tentative d'utiliser null, un booléen ou un flottant comme décalage de chaîne.
  • Tentative de lecture d'un décalage de chaîne hors limites.
  • Tentative d'affecter une chaîne vide à un décalage de chaîne.

PHP RFC : Reclassifying engine warnings

Les méthodes et comportements dépréciés ont été supprimés

  • La possibilité de supprimer une variable avec le cast (unset) ne sera plus possible.
  • Les constructeurs de classe style PHP 4 ne sont plus utilisable. Il faut remplacer le nom de la méthode constructeur par __construct. La fonction sera une fonction comme une autre.
<?php

class MaClass {
    public function MaClass() {
    }
}

Voir le résultat de l'analyse avec Phan

  • Suppression de l'argument $errcontext pour les gestionnaires d'erreur personnalisée.
  • Les constantes définies par define ne peuvent plus être insensible à la casse (le 3e argument)
  • La fonction create_function a été supprimée. Il faut les remplacer par des fonctions anonymes.
  • L'instruction each a été supprimée. Il faut la remplacer par foreach ou ArrayIterator.
  • L'utilisation de array_key_exists sur les objets n'est plus possible. Il faut remplacer par isset ou property_exists.
  • Suppression de la prise en charge des accolades pour l'accès aux données d'un tableau. PHP RFC: Deprecate curly brace syntax for accessing array elements and string offsets

Conversion d'un nombre à virgule en chaine de caractère

Avant PHP 8 la conversion d'un float en string utilisait le réglage de la locale pour le séparateur de décimales. Ce n'est plus le cas avec PHP 8.

Ceci entrainera des changements de formatage des nombres dans les applications qui utilisaient set_locale.

Modification apportée au Trait

Le code suivant ne fonctionnera plus et génèrera une erreur fatale :

trait T1 {
    function func() {}
}

trait T2 {
    function func() {}
}

class MaClass {
    use T1, T2 {
        func as otherFunc;
    }

    function func() {}
}

Voir le résultat d'analyse avec Phan

Il est nécessaire de déclarer explicitement les alias :

trait T1 {
    function func() {}
}

trait T2 {
    function func() {}
}

class MaClass {
    use T1 {
        func as otherFunc;
    }
    use T2 {
        func as otherFunc2;
    }

    function func() {}
}

Avec PHP 8, les méthodes abstraites présentes dans les traits seront vérifiées. Ainsi le code suivant est invalide :

        trait MyTrait {
            abstract private function neededByTrait(): string;
        }

        class MyClass {
            use MyTrait;

            // Error, because of return type mismatch.
            private function neededByTrait(): int { return 42; }
        }

PHP RFC : Validation for abstract trait methods

Autres modifications entrainant un changement de comportement

  • L'utilisation de "parent" dans une classe sans parent entrainera une erreur fatale lors de la compilation.
  • L'opérateur @ ne supprime plus les erreurs fatales. Il sera nécessaire d'adapter les gestionnaires d'erreur qui utilise error_reporting. Pour détecter une erreur silencieuse, il faut utiliser ce code : if (!(error_reporting() & $err_no)) { return; /* Silenced */ }
  • La priorité de l'opérateur de concaténation a changé par rapport à décalages de bits et addition ainsi que soustraction. Ainsi dans le code suivant l'opération sera réalisée avant la concaténation echo 'Total '. $a + $b;. PHP RFC : Change the precedence of the concatenation operator
  • Les fonctions désactivées sont désormais traitées exactement comme les fonctions inexistantes. L'appel d'une fonction désactivée la signalera comme inconnue et la redéfinition d'une fonction désactivée est désormais possible.
  • Les opérateurs arithmétiques et au niveau du bit (+, -, *, /, **,%, <<, >>, &, |, ^, ~, ++, -) vont maintenant systématiquement lancer une TypeError lorsque l'un des opérandes est un tableau, ressource ou objet non surchargé. La seule exception à cela est l'opération de fusion des tableaux, qui reste prise en charge. PHP RFC : Stricter type checks for arithmetic/bitwise operators

Conclusion

PHP 8 apporte de nombreuses nouveautés certaines attendue et déjà connue, car déprécié dans les précédentes versions de PHP. Utilisons le temps qu'il reste avant la sortie pour tester et corriger nos applications avec cette nouvelle version de PHP.

Nos outils d'aide à la migration tels que PHPCompatibility et Phan sont déjà en cours d'évolution pour tenir compte des nouveautés de PHP 8.

J'ai mis à disposition une version en ligne de PHPCompatibility et Phan sur le site phptools.online permettant le test de bout de code PHP.

Pendant ce temps, les frameworks tels que Symfony ont déjà commencé le travail de correction pour PHP 8.

Restez à l'écoute, je vais réaliser d'autre article sur les modifications apportées par PHP 8 ayant une incidence sur notre code.

Author avatar
Jean-Baptiste Nahan

Consultant Expert Web, j'aide les entreprises ayant des difficultés avec leur projet Web (PHP, Symfony, Sylius).

@jbnahan69 | Macintoshplus | Linkedin | JB Dev Labs