La ligne de log disait `Redirect allowed: host=trusted.example`, et la redirection est partie vers un endroit qui n'était clairement pas trusted.example. J'ai passé une longue nuit avec parse_url() et une URL qu'un navigateur lisait d'une façon pendant que notre liste d'autorisation la lisait d'une autre. Alors quand on me demande quelle est la grande nouveauté de PHP 8.5, je ne réponds pas l'opérateur pipe, même si c'est ce que répètent toutes les slides de conférence. Ma réponse, c'est l'extension URI, et je vais la défendre ici.
<?php
use Uri\Rfc3986\Uri;
$uri = new Uri('https://php.net/releases/8.5/en.php');
echo $uri->getHost(); // "php.net"D'abord, un point sur la situation. PHP 8.5 est sorti le 20 novembre 2025. Laravel 12 et 13 tournent tous les deux sur PHP 8.3 à 8.5, les hébergeurs le proposent, et la prochaine version arrive en novembre. C'est donc le bon moment pour arrêter de se demander ce qui est nouveau et commencer à se demander ce qui a vraiment changé dans nos bases de code. L'opérateur pipe récolte presque toute l'attention. Ce qui comptera dans tes rapports d'incident, c'est `Uri\Rfc3986\Uri` et son cousin WHATWG.
Voici le meilleur argument du camp d'en face, et il est solide. Les pipes changent la lecture du code sur chaque écran que tu ouvres. Les appels imbriqués qu'on lit de l'intérieur vers l'extérieur, c'est une petite taxe que tu paies toute la journée, et `|>` la supprime pour n'importe quelle fonction ordinaire, sans collection ni enveloppe `Str::of()`. Une fonctionnalité que tu croises dans cent fichiers peut facilement compter plus qu'une autre que tu utilises dans trois. Je le reconnais. J'ajouterais même que `array_first()` et `array_last()` vont faire disparaître plus d'horribles recherches à base de `array_key_last()` qu'on ne veut bien l'admettre.
Mon souci, c'est que les gains de lisibilité sont dilués, et que le pipe a quelques aspérités qui les gardent modestes. Chaque étape doit être un callable qui prend un seul argument, donc dès que tu as besoin de `str_replace`, tu écris une fonction fléchée, et en plus il faut l'entourer de parenthèses. Dans la vraie vie, les pipelines finissent en mélange de `trim(...)` et de `(fn($s) => ...)`. C'est plus agréable que l'imbrication, mais pas spectaculairement. Une équipe qui ne l'adopte jamais ne perd rien qu'une variable locale bien nommée ne puisse lui rendre.
Le parsing d'URL, c'est une autre histoire. parse_url() a toujours été laxiste : il te renvoyait un tableau pour une entrée qu'un navigateur, un proxy et ton client HTTP interpréteraient chacun à leur manière. C'est dans cet écart que naissent les open redirects et les contournements de liste d'autorisation SSRF. Désormais, tu obtiens un objet construit selon un standard publié, la RFC 3986 ou le WHATWG, et tu choisis celui qui correspond au système en face. Ce choix, c'est le vrai progrès. Tu dois décider si tu valides comme un serveur ou comme un navigateur, une question que parse_url() ne t'a jamais posée.
L'appel en lui-même est presque trop simple pour valoir la peine d'être montré, et c'est un peu là où je veux en venir. Pas besoin de refactoring, de débat sur le guide de style ni de vote d'équipe. Tu repères les endroits où un hôte ou un schéma décide de qui a le droit d'entrer, et tu remplaces le parsing.
Pour être juste envers le reste de la 8.5 : `#[\NoDiscard]` défend le même genre d'idée, en attrapant un `save()` dont personne n'a vérifié le retour false, et les erreurs fatales avec backtrace vont raccourcir certaines chasses aux dépassements de mémoire. C'est par là que j'irais ensuite. Les pipes viennent après, dans les nouveaux helpers et les data mappers, chaque fois qu'ils rendent une ligne plus claire. On est nombreux à écrire tranquillement des appels imbriqués en Go aussi, et personne n'y a laissé sa carrière.
Alors voici ma question, puisque c'est toi qui connais ta base de code, pas moi. Si tu es déjà passé à la 8.5, qu'est-ce que tu as changé en premier, et est-ce que ça a révélé un vrai bug, ou c'était uniquement pour rendre le code plus joli ? Et si tu as remplacé parse_url() par l'extension URI, est-ce que c'est la RFC 3986 ou le WHATWG qui s'est révélé le bon choix par défaut pour tes redirections et tes webhooks, et comment as-tu tranché ?




Commentaires
Pas encore de commentaire — écris le premier.
Lance la discussion
Pas de compte ni de mot de passe — saisis simplement ton adresse e-mail et nous t’envoyons un lien de connexion à usage unique. Première visite ? Tout se met en place automatiquement.
Ton évaluation sera appliquée automatiquement après ta connexion.
Vérifie ta boîte mail
Nous avons envoyé un lien de connexion à …. Ouvre-le sur cet appareil — cet onglet te connectera automatiquement.
Rien reçu ? Vérifiez le dossier spam — et marquez le message « Non spam » pour qu'il arrive directement la prochaine fois.