Tutoriel pour apprendre les nouveautés de PHP 7

Maurice Chavelli

Faut-il passer à PHP 7 (en fait 7.1) ? La question devient pertinente pour les utilisateurs de Laravel parce que la version 5.5 de ce framework imposera cette version de PHP. Alors je vous propose de faire un peu le point de ce que nous apporte ce nouveau PHP.

Déjà, on va y gagner en performances puisqu'on nous annonce un gain entre 25 % et 70 %. Bon la marge est grande !

Mais au niveau des fonctionnalités ? Vous pouvez tout trouver dans le manuel.

Pour les allergiques à l'anglais, voyons un peu ça en se limitant à ce qui semble le plus important.

Commentez

- Titre : Tutoriel pour apprendre les nouveautés de PHP 7

- Auteur : Maurice Chavelli

- Parution : 4 octobre 2017

- Licence : Copyright ® 2017 Maurice Chavelli. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Groupement des « use »

- II. Type des paramètres

- II-A. Paramètres des fonctions

- II-B. Type du retour

- III. Les opérateurs

- III-A. L'opérateur de coalescence

- III-B. L'opérateur « spaceship »

- IV. Classe anonyme

- V. Délégation des générateurs

- VI. Les exceptions

- VII. Syntaxe uniforme des variables

- VIII. Conclusion

I - Groupement des « use »

L'utilisation des espaces de noms nous amène à effectuer de nombreuses déclarations. On va pouvoir maintenant les regrouper. Prenez, par exemple, ce code :

1. use App\Http\Controllers\Controller;

2. use App\Http\Requests\CommentRequest;

3. use App\Models\Post;

4. use App\Models\Comment;

On a autant de lignes que de déclarations. On va pouvoir simplifier ainsi :

1. use App\Http\{

2. Controllers\Controller,

3. Requests\CommentRequest

4. };

5. use App\Models\{

6. Post,

7. Comment

8. };

On y gagne en clarté !

II - Type des paramètres

II-A - Paramètres des fonctions

Avec PHP 5 on peut déclarer le type des paramètres pour les interfaces, les classes et les tableaux. Avec la version 7, on peut enfin aussi déclarer les types scalaires (int, float, string, bool).

Considérez par exemple, cette fonction :

1. /**

2. * Get the next comments for the specified post.

3. *

4. * @param  \App\Models\Post  $post

5. * @param  integer $page

6. * @return array

7. */

8. public function comments(Post $post, $page)

9. {

10. ...

11. }

On a le type du premier paramètre parce que c'est un objet, mais le second, qui est un entier, on ne peut pas le déclarer.

Avec PHP 7 on peut écrire :

public function comments(Post $post, int $page)

Mais PHP ne va pas vraiment vérifier que le type est bon (allez savoir pourquoi…), il va juste s'efforcer de transformer la valeur pour la rendre conforme au type, s'il y parvient. D'ailleurs il vaut mieux se méfier de la transformation des flottants en entiers, cela peut réserver des surprises !

Mais on peut lui forcer la main pour qu'il devienne plus pointilleux :

declare(strict_types = 1);

Obligatoirement sur la première ligne du fichier PHP du code appelant.

Et là il ne laissera rien passer ! Bon, du coup c'est pas mal après d'intercepter l'erreur qui est de type TypeError.

Avec la version 7.1 est même apparu un pseudo type : iterable. Il arrive souvent que l'on transmette un paramètre qui implémente l'interface Transversable, autrement dit qui accepte l'utilisation de foreach. Dans cette catégorie on a les tableaux et les objets. On peut désormais indiquer à la fonction que l'on va lui transmettre ce genre de chose :

function action(iterable $elements)

Et rien n'empêche évidemment de déclarer une valeur par défaut :

function action(iterable $elements = [])

II-B - Type du retour

La possibilité du typage s'étend à la valeur du retour de la fonction.

Voilà, par exemple, une fonction qui renvoie un string :

1. /**

2. * Get .env element.

3. *

4. * @param string $key

5. * @return string

6. */

7. public function get($key)

8. {

9. return $this->env->get ($key);

10. }

On ne précise pas ici le type de la valeur que l'on renvoie, juste dans les commentaires. Avec PHP 7 on peut écrire :

public function get($key) : string

Là aussi si on veut un comportement « strict » il faut le préciser de la même manière que l'on a vue ci-dessus.

On peut aussi déclarer le type de retour iterable.

III - Les opérateurs

III-A - L'opérateur de coalescence

Je suppose que vous avez souvent l'occasion d'écrire du code dans ce genre :

$category = isset($request->category) ? $request->category : 'aucune';

PHP 7 nous offre un nouvel opérateur :

$category = $request->category ?? 'aucune';

Le résultat est le même, mais c'est plus concis !

III-B - L'opérateur « spaceship »

Prenons ce code qui permet de classer des éléments :

usort($element, function ($a, $b) {
return ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
});

On a :

- a < b : -1 ;

- a = b : 0 ;

- a > b : 1.

Avec PHP 7 on peut simplifier la syntaxe :

usort($element, function ($a, $b) {
return $a <=> $b;
});

Pratique ! Par contre, ça ne me fait pas vraiment penser à un vaisseau spatial, mais bon…

IV - Classe anonyme

Avec PHP 5 on a hérité des fonctions anonymes qui sont, il faut l'avouer, bien pratiques surtout comme fonctions de rappel.

Avec PHP 7 ce sont maintenant les classes qui peuvent devenir anonymes. Autrement dit on n'a pas besoin de faire toutes les déclarations. Voici un exemple :

1. $maClasseAnonyme = new class($parametre) {

2. private $parametre;

3. public function __construct($parametre) {

4. $this->parametre = $parametre;

5. }

6. };

À part d'être anonymes, on les utilise exactement comme les autres : implémentation d'interfaces, héritages, traits.

J'avoue que je ne vais pas m'en servir tous les jours.

V - Délégation des générateurs

Si vous n'êtes pas familiarisé avec les générateurs alors, commencez par vous renseigner à leur sujet. C'est une façon de fournir des éléments d'un ensemble (itérateur) sans être obligé de construire au départ cet ensemble, donc de ne pas affecter outre mesure la mémoire.

Ce n'est pas clair ? Voici un exemple :

1. function entiers() {

2. for ($i = 0; $i <= 10; ++$i) {

3. yield $i;

4. }

5. }

7. foreach (entiers() as $number) {

8. echo "$number ";

9. }

11. // Résultat : 0 1 2 3 4 5 6 7 8 9 10

Oui c'est un peu idiot comme exemple, mais c'est pour le principe !

La délégation c'est le fait pour un générateur d'en appeler un autre :

1. function entiers() {

2. for ($i = 0; $i <= 5; ++$i) {

3. yield $i;

4. }

5. }

7. function nombres() {

8. yield 100;

9. yield from entiers ();

10. yield 101;

11. yield from entiers ();

12. }

14. foreach (nombres() as $number) {

15. echo "$number ";

16. }

18. // Résultat : 100 0 1 2 3 4 5 101 0 1 2 3 4 5

Bon ce n'est pas plus malin comme exemple, mais au moins ça donne le principe.

VI - Les exceptions

Les exceptions ont été apportées à PHP à partir de la version 5. Mais ça ne concerne que les objets et toutes les autres erreurs de PHP ne passent pas par là. D'autre part, il est en général fait usage d'un gestionnaire par défaut avec la fonction set_exception_handler.

PHP 7 apporte l'interface Throwable qui concerne les exceptions et, c'est nouveau, les erreurs, parce qu'elle se place en tête de la hiérarchie.

Prenons ce code :

1. function test($object)

2. {

3. return $object->riendutout();

4. }

5. test(null);

6. echo 'Je marche encore !';

Si je l'exécute, je vais tomber immanquablement sur une erreur fatale : Call to a member function riendutout() on null…

On va maintenant intercepter cette erreur :

1. function test($object)

2. {

3. return $object->riendutout();

4. }

5. try

6. {

7. test(null);

8. } catch(Error $e)

9. {

10. echo $e->getMessage(), PHP_EOL;

11. }

12. echo 'Je marche encore !';

À l'exécution (PHP 7), on obtient :

Call to a member function riendutout() on null
Je marche encore !

On peut ainsi tout intercepter, même les divisions par zéro !

VII - Syntaxe uniforme des variables

Avec PHP on peut utiliser des variables de variables, même si ce n'est pas très indiqué parce que ça complique la lecture du code et on peut, en général, facilement s'en passer.

Regardez ce code :

$identite = ['nom' => 'Pierre'];
$Pierre = 'Paul';
echo $$identite['nom'];

Avec PHP 5 vous obtenez : Pierre.

Avec PHP 7 vous obtenez plein d'erreurs : Array to string conversion…

Que se passe-t-il ?

PHP 7 apporte la « syntaxe uniforme des variables », un truc qui couvait depuis quelques années avec pas mal d'opposition à cause du cassage du code antérieur. Mais finalement c'est passé dans cette version.

Normalement l'interprétation se fait de gauche à droite, donc on devrait commencer par $$identite, puis prendre l'offset. Mais PHP 5 ne fait pas ça, il commence par traiter $identite['nom']. Par contre comme PHP 7 va scrupuleusement de gauche à droite il y a un gros souci. Pour que ça fonctionne, on doit écrire ${$identite['nom']}. Et là maintenant ça fonctionne !

Ce changement n'est pas anodin si vous voulez migrer du code en PHP 7 !

VIII - Conclusion

On voit qu'il y a pas mal de nouveautés dans cette version, et je n'ai pas parlé des choses plus ou moins anodines que vous pouvez trouver dans le manuel.