PHP 8.5 : les nouveautés de la nouvelle version majeure

20/11/2025
Pierre Gouedar Round

Pierre Gouedar

PHP Logo

Ça y est, PHP 8.5 est disponible depuis le 20 novembre 2025. Pour fêter ses 30 ans, le langage nous offre enfin des outils qu'on espérait voir intégrés depuis longtemps : le pipe operator, une gestion des URI remise au goût du jour et la syntaxe clone with. Cette mise à jour va permet d'assainir notre code au quotidien. 

Qu'est-ce que PHP ?

PHP est un langage de programmation principalement utilisé pour le développement web. Créé en 1995 par Rasmus Lerdorf, PHP alimente aujourd'hui plus de 75% des sites web dans le monde. Sa simplicité d'apprentissage, sa flexibilité et son écosystème riche en frameworks en font un choix privilégié pour les applications web de toutes tailles.

Les nouveautés et améliorations de la version 8.5 de PHP

Avec la version 8.5, PHP ne se contente pas d'évoluer, il introduit de nouvelles fonctionnalités attendues depuis longtemps par les développeurs. Cette mise à jour se concentre sur trois axes majeurs : la lisibilité du code, la manipulation sécurisée des URLs, et le support amélioré des classes readonly.

Le Pipe Operator (|>)

Le pipe operator est sans doute la fonctionnalité la plus attendue de PHP 8.5. Il permet de chaîner des appels de fonctions de manière fluide, en passant le résultat d'une expression comme premier argument de la fonction suivante.

Avant (approche classique)

<?php

$title = ' PHP 8.5 Released ';

$slug = strtolower(
    str_replace('.', '',
        str_replace(' ', '-',
            trim($title)
        )
    )
);

echo $slug; // "php-85-released"

Le code se lit de l'intérieur vers l'extérieur, ce qui devient rapidement illisible avec plusieurs transformations.

Après (avec le pipe operator)

<?php

$title = ' PHP 8.5 Released ';

$slug = $title
    |> trim(...)
    |> (fn($str) => str_replace(' ', '-', $str))
    |> (fn($str) => str_replace('.', '', $str))
    |> strtolower(...);

echo $slug; // "php-85-released"

Le code se lit maintenant de gauche à droite, de haut en bas, de manière naturelle. Chaque étape de transformation est clairement visible.

Fonctionnement technique

Le pipe operator fonctionne entièrement au niveau du compilateur. L'expression :

$result = $value |> callable(...);

Est transformée en :

$result = callable($value);

Cela signifie qu'il n'y a aucun impact sur les performances à l'exécution.

L'extension URI

PHP a été conçu pour le web, et le web fonctionne avec des URLs. Pourtant, la fonction historique parse_url() ne suivait aucun standard et était explicitement documentée comme ne devant pas être utilisée avec des URLs non fiables ou malformées.

PHP 8.5 introduit une nouvelle extension URI qui respecte les standards RFC 3986 et WHATWG URL, utilisée par les bibliothèques comme uriparser et Lexbor.

Avant (avec parse_url)

<?php 

$url = 'https://api.example.com:8080/users?id=123&sort=name#profile';
$parts = parse_url($url);

echo $parts['scheme'];   // https
echo $parts['host'];     // api.example.com
echo $parts['port'];     // 8080
echo $parts['path'];     // /users
echo $parts['query'];    // id=123&sort=name
echo $parts['fragment']; // profile

Problèmes : pas de validation, pas de normalisation, comportement incohérent sur les URLs malformées.

Après (avec Uri\Rfc3986\Uri)

<?php

use Uri\Rfc3986\Uri;

$uri = new Uri('https://api.example.com:8080/users?id=123&sort=name#profile');

echo $uri->getScheme();   // https
echo $uri->getHost();     // api.example.com
echo $uri->getPort();     // 8080
echo $uri->getPath();     // /users
echo $uri->getQuery();    // id=123&sort=name
echo $uri->getFragment(); // profile

Modification fluide et immutable

Les objets Uri sont immutables. Les modifications créent de nouvelles instances :

<?php

use Uri\Rfc3986\Uri;

$uri = new Uri('http://example.com/old-path');

$newUri = $uri
    ->withScheme('https')
    ->withPath('/new-path')
    ->withQuery('updated=true');

echo $newUri->toString();
// https://example.com/new-path?updated=true

Deux standards disponibles

PHP 8.5 propose deux classes selon le standard souhaité :

  • Uri\Rfc3986\Uri : Suit le RFC 3986 (URIs génériques, validation stricte)
  • Uri\WhatWg\Url : Suit le standard WHATWG URL (comportement des navigateurs, support Unicode/IDNA)
<?php

use Uri\Rfc3986\Uri;
use Uri\WhatWg\Url;

// RFC 3986 - strict
$rfc = Uri::parse("https://example.com/path?x=1");

// WHATWG - comportement navigateur
$whatwg = Url::parse("https://example.com/path?x=1");

// Gestion des erreurs
$errors = [];
$bad = Url::parse(" invalid url", null, $errors);
// $bad est null, $errors contient les détails

Clone With

Depuis PHP 8.1 et les propriétés readonly, cloner un objet et modifier ses propriétés était devenu problématique. PHP 8.5 résout élégamment ce problème avec la nouvelle syntaxe clone().

Avant (approche fastidieuse)

<?php

readonly class Color
{
    public function __construct(
        public int $red,
        public int $green,
        public int $blue,
        public int $alpha = 255,
    ) {}

    public function withAlpha(int $alpha): self
    {
        // Workaround complexe
        $values = get_object_vars($this);
        $values['alpha'] = $alpha;
        return new self(...$values);
    }
}

$blue = new Color(79, 91, 147);
$transparentBlue = $blue->withAlpha(128);

Après (avec clone with)

<?php

readonly class Color
{
    public function __construct(
        public int $red,
        public int $green,
        public int $blue,
        public int $alpha = 255,
    ) {}

    public function withAlpha(int $alpha): self
    {
        return clone($this, [
            'alpha' => $alpha,
        ]);
    }
}

$blue = new Color(79, 91, 147);
$transparentBlue = $blue->withAlpha(128);

echo $blue->alpha;            // 255
echo $transparentBlue->alpha; // 128

L'attribut #[\NoDiscard]

Le nouvel attribut #[\NoDiscard] permet de signaler qu'une valeur de retour ne doit pas être ignorée. PHP émettra un warning si le résultat n'est pas utilisé.

<?php

#[\NoDiscard("Le résultat du traitement peut contenir des erreurs")]
function bulk_process(array $items): array
{
    // Traitement...
    return $results;
}

// Warning: The return value of function bulk_process() should
// either be used or intentionally ignored by casting it as (void)
bulk_process($items);

// OK - résultat utilisé
$results = bulk_process($items);

// OK - ignoré explicitement
(void) bulk_process($items);

Cette fonctionnalité améliore la sécurité des APIs en évitant les bugs silencieux où une valeur de retour importante est accidentellement ignorée.

Closures dans les expressions constantes

Les closures statiques et les callables de première classe peuvent maintenant être utilisés dans les expressions constantes, notamment dans les attributs :

<?php 

#[SkipDiscovery(static function (Container $container): bool {
    return ! $container->get(Application::class) instanceof ConsoleApplication;
})]
final class BlogPostEventHandlers
{
    // ...
}

Note importante : Ces closures doivent être explicitement marquées comme static et ne peuvent pas accéder à des variables externes avec use.

Nouvelles fonctions pour les tableaux

PHP 8.5 ajoute deux fonctions très attendues pour récupérer le premier et le dernier élément d'un tableau :

<?php

$users = ['Alice', 'Bob', 'Charlie'];

$first = array_first($users); // 'Alice'
$last = array_last($users);   // 'Charlie'

// Fonctionne avec les tableaux associatifs
$data = ['name' => 'John', 'age' => 30, 'city' => 'Paris'];
echo array_first($data); // 'John'
echo array_last($data);  // 'Paris'

// Retourne null pour les tableaux vides
$empty = [];
var_dump(array_first($empty)); // null
var_dump(array_last($empty));  // null

// Combinaison avec l'opérateur null coalescent
array_first($empty) ?? 'valeur par défaut'; // 'valeur par défaut'

Ces fonctions complètent array_key_first() et array_key_last() introduites en PHP 7.3.

Backtraces pour les erreurs fatales

Le debugging devient plus facile avec l'affichage automatique des stack traces pour les erreurs fatales :

Fatal error: Maximum execution time of 1 second exceeded in example.php on line 6

Stack trace:
#0 example.php(6): usleep(100000)
#1 example.php(7): recurse()
#2 example.php(7): recurse()
#3 example.php(7): recurse()
...
#10 example.php(10): recurse()
#11 {main}

Cette fonctionnalité est contrôlée par le paramètre INI fatal_error_backtraces (activé par défaut).

Nouvelles fonctions de récupération des handlers

// Récupérer le handler d'erreur actuel
$currentErrorHandler = get_error_handler();

// Récupérer le handler d'exception actuel
$currentExceptionHandler = get_exception_handler();

Ces fonctions sont particulièrement utiles pour les frameworks et CMS modulaires qui veulent chaîner ou ajuster leur logique de gestion d'erreurs.

Constante PHP_BUILD_DATE

Une nouvelle constante permet de connaître la date de compilation de PHP :

<?php

echo PHP_BUILD_DATE; // "Nov 20 2025 10:30:45"

// Utile pour le debugging en production
echo 'PHP Version: ' . PHP_VERSION . "\n";
echo 'Build Date: ' . PHP_BUILD_DATE . "\n";

Amélioration de cURL

La nouvelle fonction curl_multi_get_handles() facilite la gestion des sessions cURL multiples :

<?php

$multiHandle = curl_multi_init();
$ch1 = curl_init('https://api.example.com/users');
$ch2 = curl_init('https://api.example.com/posts');

curl_multi_add_handle($multiHandle, $ch1);
curl_multi_add_handle($multiHandle, $ch2);

// Nouveau en PHP 8.5 : récupérer tous les handles
$handles = curl_multi_get_handles($multiHandle);
// Retourne: [$ch1, $ch2]

// Exécution et traitement
$running = null;
do {
    curl_multi_exec($multiHandle, $running);
} while ($running > 0);

foreach ($handles as $handle) {
    $response = curl_multi_getcontent($handle);
    curl_multi_remove_handle($multiHandle, $handle);
}

De plus, les handles cURL peuvent maintenant être persistés entre plusieurs requêtes PHP, évitant le coût de réinitialisation des connexions.

OPcache toujours compilé

À partir de PHP 8.5, l'extension OPcache est toujours compilée statiquement dans PHP (comme ext/dateext/hashext/pcre). Son activation reste contrôlée par les paramètres INI (opcache.enable).

Option CLI --ini=diff

Une nouvelle option CLI permet d'afficher uniquement les paramètres INI modifiés :

php --ini=diff

# Exemple de sortie :
# memory_limit = 256M (default: 128M)
# max_execution_time = 60 (default: 30)

Dépréciations importantes

PHP 8.5 prépare le terrain pour PHP 9.0 avec plusieurs dépréciations :

Fonctionnalité Alternative
__sleep() et __wakeup() __serialize() et __unserialize()
Syntaxe ${var} en interpolation {$var}
Case avec point-virgule au lieu de deux-points case X:
null comme offset de tableau Chaîne vide ''
Backticks pour l'exécution shell shell_exec()

Récapitulatif des différences entre PHP 8.4 et 8.5

Fonctionnalité PHP 8.4 PHP 8.5
Pipe Operator Non disponible \|> disponible
Extension URI Non disponible RFC 3986 + WHATWG URL
Clone With Non disponible clone($obj, [...])
#[\NoDiscard] Non disponible Disponible
Closures en constantes Non disponible Disponible (static)
array_first() / array_last() Non disponible Disponible
Backtraces erreurs fatales Non disponible Activé par défaut
OPcache Extension optionnelle Toujours compilé
Property Hooks Disponible Disponible
Lazy Objects Disponible Disponible

Support et maintenance

Version Sortie Fin support bugs Fin support sécurité
PHP 8.5 Nov 2025 Déc 2027 Déc 2029
PHP 8.4 Nov 2024 Déc 2026 Déc 2028
PHP 8.3 Nov 2023 Déc 2025 Déc 2027

Conseils de migration

Comme à chaque nouvelle version majeure, il est préférable de patienter jusqu'à la première release de correctifs (8.5.1) avant d'envisager une mise en production. Les retours de la communauté dans les premières semaines permettent d'identifier et corriger les problèmes passés entre les mailles du filet.
Avant toute migration, une analyse statique avec PHPStan ou Psalm permet de détecter rapidement les incompatibilités dans votre codebase. Pensez également à consulter la liste des dépréciations : des fonctionnalités courantes comme __sleep() ou la syntaxe ${var} disparaîtront dans PHP 9.
Pour les projets de taille importante, Rector peut automatiser une partie significative des adaptations de code et faire gagner un temps précieux.

Conclusion

Au final, cette version 8.5 est bien plus qu'une étape de transition vers PHP 9. Elle concrétise des attentes de longue date : on pense évidemment au pipe operator pour la fluidité, mais aussi à la gestion enfin standardisée des URL et à la souplesse apportée aux classes readonly via clone with.

Les ajouts comme #[\NoDiscard] ou les fonctions sur les tableaux montrent aussi un souci du détail très appréciable au quotidien. PHP a 30 ans, mais il n'a jamais été aussi agréable à écrire. Si vous n'avez pas encore migré, c'est le moment d'y passer pour gagner en robustesse et en propreté. 

Ressources et Documentation


Pierre Gouedar Round

Pierre Gouedar

Partager l'article

Partager sur linkedinPartager sur facebook

Pour aller plus loin...

Coolify Docs 2026 01 23 09 10
Développement web
Coolify : reprendre le contrôle de votre hébergement sans devenir expert DevOps

Coolify : réduisez vos coûts cloud de 70 % avec cette alternative open source à Vercel. Déploiement simple, données souveraines. Guide complet pour DSI/CTO.

Lire l'article

Vous souhaitez être accompagné pour lancer votre projet digital ?

Koul Logo Blanc Sans Fond
4 Rue Maurice Prevost, 51450 Béthenycontact@koul.io
BlogInstagramFacebookLinkedin
À propos
Qui sommes-nous ?L'histoireNos projetsNous contacter
KOUL 2026
Mentions légalesCGV