PHP 7.2 est sorti le 30 novembre. La grande nouvelle n’est pas une nouvelle fonctionnalité, c’est une suppression. mcrypt disparaît.

C’est une bonne chose, même si ça ne le semble pas quand c’est vous qui devez faire la migration.

Le problème mcrypt

mcrypt n’est plus maintenu depuis 2007. Plus d’une décennie de stagnation dans une bibliothèque cryptographique. Dépréciée en 7.1, elle est retirée définitivement en 7.2. Son remplaçant : sodium, désormais intégré comme extension core.

Sodium est le binding PHP pour libsodium, une bibliothèque cryptographique moderne conçue autour de valeurs par défaut sûres. Là où mcrypt vous demandait de choisir le bon algorithme, le bon mode et le bon padding (et vous laissait vous planter silencieusement), l’API de sodium rend les choix dangereux structurellement difficiles. sodium_crypto_secretbox() pour le chiffrement symétrique, sodium_crypto_box() pour l’asymétrique, sodium_crypto_sign() pour les signatures. Les noms disent ce qu’on fait.

Si vous avez du code mcrypt en production, la migration est inévitable. Et ça vaut le coup de le faire soigneusement : du code cryptographique qui “fonctionne encore” peut être silencieusement cassé d’une façon que vous ne remarquerez qu’il sera trop tard.

Le type hint object

7.2 ajoute object comme type de paramètre et de retour :

function serialize(object $data): string {
    // accepte n'importe quel objet
}

C’est large — n’importe quel objet le satisfait — mais c’est mieux qu’aucun type du tout quand vous ne vous souciez vraiment pas de la classe spécifique. Complète les types existants array, callable et les hints par classe concrète.

Argon2 dans password_hash

$hash = password_hash($password, PASSWORD_ARGON2I);

PASSWORD_BCRYPT était la valeur par défaut et reste raisonnable, mais Argon2 a remporté le Password Hashing Competition pour une bonne raison : il est memory-hard, ce qui rend le craquage par GPU significativement plus coûteux. Vaut la peine de basculer pour les nouvelles apps.

7.2 est davantage une version sécurité qu’une version langage. Supprimez mcrypt, ajoutez sodium, et vous placez la plateforme dans un état où on peut lui faire confiance avec des données sensibles. Les fonctionnalités du langage sont incrémentales. Le changement d’infrastructure, lui, ne l’est pas.

Des types de paramètres qu’on peut désormais omettre intentionnellement

7.2 formalise quelque chose qui était jusqu’ici juste une odeur de code : quand vous implémentez une interface ou surchargez une méthode, vous pouvez maintenant omettre complètement le type du paramètre. C’est de la contravariance valide au sens du principe de substitution de Liskov.

interface Serializable {
    public function serialize(array $data): string;
}

class JsonSerializer implements Serializable {
    public function serialize($data): string { // pas de type — accepte plus, toujours valide
        return json_encode($data);
    }
}

Ça paraît bizarre au premier abord. Mais c’est logiquement correct : une méthode qui accepte tout est strictement plus permissive qu’une qui n’accepte que des tableaux. Le système de types est d’accord, même si votre relecteur de code lève un sourcil.

Des méthodes abstraites qui évoluent

Quand une classe abstraite étend une autre classe abstraite, elle peut désormais surcharger la méthode abstraite avec une signature différente. La contrainte est directionnelle : les paramètres peuvent être élargis (contravariants), les types de retour peuvent être resserrés (covariants).

abstract class BaseProcessor {
    abstract function process(string $input);
}

abstract class TypedProcessor extends BaseProcessor {
    abstract function process($input): int; // paramètre élargi, type de retour ajouté
}

C’était refusé avant 7.2. Ça débloque des abstractions intermédiaires sans forcer chaque classe feuille à répéter la même signature.

Virgule finale dans les imports groupés

Petit, mais je remarque son absence quand elle manque. Les imports de namespaces groupés peuvent désormais avoir une virgule finale après le dernier élément :

use App\Services\{
    UserService,
    OrderService,
    NotificationService, // virgule ici — enfin
};

Ça signifie qu’on peut réordonner ou ajouter des lignes sans toucher à la ligne précédente. Les diffs git deviennent plus propres, les conflits de merge plus rares.

count() a développé une conscience

Avant 7.2, count(null) retournait 0. Silencieusement. Sans warning. C’est exactement le genre de chose qui enterre un bug pendant des mois. Maintenant, ça émet un E_WARNING quand vous passez quelque chose qui n’est ni un tableau ni un objet Countable.

count(null);  // Warning: count(): Parameter must be an array or an object that implements Countable
count(42);    // pareil
count("hi");  // pareil

Le comportement n’a pas changé pour les entrées valides. Seul le silence a été brisé. C’est la bonne direction.

spl_object_id() — ce que vous émuliez avec SplObjectStorage

Si vous avez déjà construit une map indexée par identité d’objet, vous avez écrit quelque chose comme ça :

$storage = new SplObjectStorage();
$storage[$obj] = true;

7.2 ajoute spl_object_id(), qui retourne un entier unique pour la durée de vie d’un objet. C’est le même handle interne qu’utilise SplObjectStorage, rendu directement accessible :

$id = spl_object_id($obj); // ex. 42
$map[$id] = 'something';

L’entier est réutilisé après la destruction de l’objet, donc ne le conservez pas au-delà de la durée de vie de l’objet. Dans un contexte bien délimité cependant, c’est une clé d’identité peu coûteuse.

PDO : les chaînes de caractères nationales

Quand on travaille avec des bases de données qui distinguent les types de chaînes régulières et nationales (Oracle, SQL Server), 7.2 ajoute les flags nécessaires :

$stmt = $pdo->prepare("SELECT * FROM users WHERE name = ?");
$stmt->bindValue(1, 'Ångström', PDO::PARAM_STR | PDO::PARAM_STR_NATL);

Ou définir une valeur par défaut au niveau de la connexion :

$pdo->setAttribute(PDO::ATTR_DEFAULT_STR_PARAM, PDO::PARAM_STR_NATL);

PDO::PARAM_STR_NATL indique que la chaîne est un type caractère national (NCHAR/NVARCHAR). Obscur, certes. Indispensable si vous avez déjà vu vos données Unicode ressortir déformées parce que le driver ne faisait pas la différence.

GD supporte les BMP et les rectangles de clipping

Deux choses à connaître. D’abord, les fichiers BMP sont désormais des citoyens de première classe dans l’extension GD :

$image = imagecreatefrombmp('photo.bmp');
imagebmp($image, 'output.bmp');

Ensuite, on peut maintenant définir un rectangle de clipping pour que les opérations de dessin n’affectent qu’une portion de l’image :

imagesetclip($image, 10, 10, 200, 150); // x1, y1, x2, y2
// tout ce qui est dessiné en dehors de ce rectangle est silencieusement ignoré

Aucune de ces fonctionnalités ne transforme la façon dont la plupart des apps fonctionnent, mais les deux remplacent “installer une bibliothèque supplémentaire” par “c’est juste dans le core maintenant.”

mb_chr() et mb_ord() — le chr() et ord() d’Unicode

PHP a chr() et ord() depuis toujours. Ils travaillent sur des octets. Pour les points de code Unicode, vous étiez livré à vous-même. 7.2 ajoute les équivalents multibyte :

$char = mb_chr(0x1F600); // retourne l'emoji 😀
$code = mb_ord('é');     // retourne 233

Et mb_scrub(), qui supprime les séquences d’octets invalides d’une chaîne plutôt que d’échouer silencieusement ou de lancer une exception :

$clean = mb_scrub($untrustedInput, 'UTF-8');

Pratique à toute frontière externe : réponses API, uploads de fichiers, lectures en base depuis des systèmes legacy.

Dépréciations à connaître avant l’arrivée de 7.4

Plusieurs choses ont été mollement dépréciées en 7.2 et deviendront des erreurs dans les versions ultérieures. Celles qui risquent le plus de piquer :

__autoload() est déprécié. Si vous enregistrez encore une fonction d’autoload globale au lieu d’utiliser spl_autoload_register(), corrigez ça avant que ça devienne fatal.

create_function() est déprécié. C’est un wrapper autour de eval() et ça a toujours été dangereux. Utilisez une closure :

// avant
$fn = create_function('$x', 'return $x * 2;');

// après
$fn = fn($x) => $x * 2;

each() est déprécié. Le pattern de boucle qu’il permettait s’écrit mieux avec foreach. Aucune perte ici.

parse_str() sans second argument déverse les valeurs parsées dans la table des symboles locale — un problème de sécurité qui n’aurait jamais dû être autorisé. Passez toujours la variable de sortie :

parse_str($queryString, $params); // correct

Le cast (unset) est déprécié parce qu’il retourne toujours null, que vous pouvez simplement écrire null. Une syntaxe complètement inutile qui n’aurait jamais dû exister.