Craftyx Blog

Typehint pour les types scalaires pour PHP 7

Typehint pour les types scalaires pour PHP 7

La future grosse version de PHP, dénommée PHP7 (oui oui, on zappe la version 6) a passé l'étape de feature freeze. C'est une étape à partir de laquelle les développeurs décident de ne plus accepter de nouvelles fonctionnaltées pour la 7.0, et que seules celles déjà votées mais non implémentées seront ajoutées. Parmis ces nouveautés se cachent deux que j'attend particulièrement : la déclaration du type de retour et le typehint pour les types scalaire. Nous allons parler de ce dernier dans cet article.

Types scalaires

Les types scalaires sont les types les plus simples en PHP, ce sont sont avec lesquels vous avez appris à utiliser le langage : bool, int, float, string.

Ce sont des types extremement courants dans vos développement quotidiens, je pense que l'on peut se passer de beaucoup plus d'explications.

Le Typehint

Le typehint permet d'imposer à une fonction d'accepter uniquement des données d'un certain type. Introduit avec PHP 5.0, cela vous permet d'être certain que ce que vous recevez dans votre fonction est effectivement une données du type souhaité.

function formatDateInFrench(DateTime $date)
{
    return $date->format('d/m/Y');
} 

Vous n'avez pas besoin de alors de vous demander si $date est du type DateTime, vous avez la garantie qu'il l'est. Si un objet d'un autre type est passé en paramètre, une Fatal Error sera lancé.

Sont accépté aujourd'hui en tant que type possible de typehint :

  • N'importe quelle classe, par son nom
  • Une interface, par son nom
  • un tableau, par le mot clé array
  • un callable, par le mot clé callable

Exemple :

public function registerUser(UserInterface $user, array $options)
{
    // create a user
}

Dernière petite chose à savoir, si vous definissez une valeur par défaut à null sur un typehint, alors la valeur null sera acceptée. Sinon, fatal error.

function formatDateInFrench(DateTime $date = null)
{
    return is_null($date) ? date('d/m/Y') : $date->format('d/m/Y');
} 

Scalar typehint

Grâce à PHP7, il est donc possible de faire du scalar typehint ! Si vous avez compris les deux blocs au dessus, alors vous saisissez l'idée : forcer un type de données en entrée d'une fonction. Oui, et non...

Pour résoudre des conflits de guerre politique au sein des boss de PHP, Il existe deux différent cas d'usage du scalar type hint : Weak & Strict

Weak scalar typehint

Le weak scalar typehint vous assure que les arguments typehinté (franglish) seront bien du type demandé. Cependant, le type d'entrée n'est pas forcé, une conversion sera effectuée par php.

Le weak scalar typehint sera le mode de typehint actif par défaut

<?php

function add(int $a, int $b)
{
    return $a + $b;
}

sum("4", 2); // int(6)

Voici le tableau des conversions possibles :

Type declaration int float string bool object
int oui oui* oui† oui non
float oui oui oui† oui non
string oui oui oui oui oui‡
bool oui oui oui oui non

* seul les float entre PHP_INT_MIN et PHP_INT_MAX sont accéptés.

† Les string non numériques pas accéptées. Les string numériques avec des lettres derrières les chiffres sont accéptées, mais produisent une notice.

‡ Seulement si la méthode __toString existe.

Strict scalar typehint

Le mode strict est un mode beaucoup plus réaliste et évident à mon gout. Il existe une particularité cependant, qui permet qu'un int soit considéré comme un float.

L'activation de ce mode est, tristement, à effectuer fichier par fichier. Par d'options globales dans le php.ini donc pour forcer ce mode. Pour l'activer, vous devez ajouter en toute première place dans votre fichier php, l'instruction : declare(strict_types=1);

Voilà un exemple :

<?php
declare(strict_types=1);

function add(int $a, int $b) {
    return $a + $b;
}

add(1, 2); // int(3)

Un autre avec la particularité :

<?php
declare(strict_types=1);

function add(float $a, float $b) {
    return $a + $b;
}

add((1, 2); // float(3)

Bien sûr comme pour la typehint d'objet, si un string est passé à la place d'un float, une fatal error sera lancée.

In the end

Le point positif de tout ça, c'est que cela nous permet de créer une API robuste pour applications, si on attend un int on ne veut pas d'une string, etc. L'histoire de l'implémentation de cette fonctionnalité est une longue histoire politique au sein des membres décideurs de PHP, qui tourne depuis au moins Novembre 2O14, et le résultat final est un compromis afin d'obtenir les 2/3 des votes "oui" nécessaire à l'acceptation de la feature.

Je trouve dommage que l'on soit obligé de passer par un declare(strict_types=1), mais je comprend l'idée derrière les problèmes de portabilités des projets etc, il fallait faire un choix.

Pour terminer, je vais vous montrer un exemple de typehint scalaire, couplé à la fonctionnalité dont je vous ai également parlé en intro, la déclaration du type de route :

public function divide(float $a, float $b): float
{
    return $a/$b;
}

Par l'ajout d'un : type à l'arrière de la fonction, nous avons la garanti d'avoir un float au retour. Excellent non ?

Tout ça me laisser envisager un PHP de plus en plus professionel, où la qualité et la rigueur prendra une autre forme au sein des équipes de développement, que ce soit par ce genre d'ajout ou par l'adoption de plus en plus forte des outils de qualité (TDD, DDD, etc). Que pensez vous de ce changement dans la langage ?

Julien Tant Par