PHP, le langage qui propulse plus de 75 % des sites web mondiaux, continue son évolution fulgurante vers une maturité accrue en termes de typage et de performance. En 2025, avec PHP 8.4 fraîchement installé dans les environnements de production et PHP 8.5 qui pointe le bout de son nez pour novembre, il est temps de faire le point. Cet article solide décrypte en profondeur declare(strict_types=1), les mises à jour phares de PHP 8.4, et les avancées attendues pour PHP 8.5. Que vous soyez un développeur Laravel, Symfony ou vanilla PHP, ces évolutions renforcent la robustesse et la lisibilité de votre code.
Nous nous basons sur les RFC officiels, les annonces de la communauté PHP et les retours d'expérience pour une analyse technique approfondie, avec des exemples concrets et des conseils pratiques.
declare(strict_types=1) : Le Rempart Contre les Erreurs de Typage Silencieuses
Introduit en PHP 7.0 (2016), declare(strict_types=1) est une directive qui active le typage strict au niveau d'un fichier. Contrairement au typage faible par défaut de PHP (qui convertit automatiquement les types, comme '5' en 5), cette déclaration force une vérification exacte des types lors des appels de fonctions. C'est un outil essentiel pour éviter les bugs subtils, améliorer la maintenabilité et aligner PHP sur des langages plus rigoureux comme TypeScript ou Java.
Comment Ça Marche ?
- Portée : Limité à un fichier PHP (pas global). Placez-le en haut du fichier, avant tout code.
- Impact : Affecte les types de paramètres des fonctions et méthodes déclarées dans ce fichier. Les appels entrants doivent matcher exactement (pas de coercion).
- Types supportés : Scalaires (
int,float,string,bool), composés (array,object,callable,iterable), et unions/intersections depuis PHP 8.0+. - Retour des fonctions : Le typage strict s'applique aussi aux types de retour si déclarés.
Avantages
- Détection précoce d'erreurs : Les mismatches de types lèvent une
TypeErrorau runtime, au lieu de résultats inattendus. - Meilleure IDE et outils statiques : PhpStorm, Psalm ou PHPStan exploitent cela pour une autocomplétion et une analyse plus précises.
- Code plus prévisible : Réduit les surprises en production, idéal pour les équipes.
- Migration vers le typage fort : Facilite l'adoption progressive des attributs typed properties (PHP 7.4+).
Exemple Basique : Sans vs Avec Strict Types
Sans strict_types (typage faible – défaut) :
1<?php2function addition(int $a, int $b): int {3 return $a + $b;4}56echo addition('5', 3); // Affiche 8 (conversion '5' → 5)1<?php2function addition(int $a, int $b): int {3 return $a + $b;4}56echo addition('5', 3); // Affiche 8 (conversion '5' → 5)
Avec strict_types (typage strict) :
1<?php2declare(strict_types=1);34function addition(int $a, int $b): int {5 return $a + $b;6}78echo addition('5', 3); // TypeError: Argument 1 must be of type int, string given1<?php2declare(strict_types=1);34function addition(int $a, int $b): int {5 return $a + $b;6}78echo addition('5', 3); // TypeError: Argument 1 must be of type int, string given
Ici, PHP refuse la conversion automatique, forçant un cast explicite : addition((int)'5', 3).
Exemple Avancé : Dans une Classe avec Unions
1<?php2declare(strict_types=1);34class User {5 public function __construct(6 public readonly string|int $id, // Union type (PHP 8.0+)7 public string $name8 ) {}910 public function greet(): string {11 return "Hello, {$this->name}! ID: {$this->id}";12 }13}1415// Usage16$user = new User(123, "Alice"); // OK : int pour id17$user2 = new User("user-456", "Bob"); // OK : string pour id1819// Erreur si non-strict : $user3 = new User(true, "Charlie"); // true → 1 (int)20$user3 = new User(true, "Charlie"); // TypeError : Argument 1 must be of type string|int, bool given1<?php2declare(strict_types=1);34class User {5 public function __construct(6 public readonly string|int $id, // Union type (PHP 8.0+)7 public string $name8 ) {}910 public function greet(): string {11 return "Hello, {$this->name}! ID: {$this->id}";12 }13}1415// Usage16$user = new User(123, "Alice"); // OK : int pour id17$user2 = new User("user-456", "Bob"); // OK : string pour id1819// Erreur si non-strict : $user3 = new User(true, "Charlie"); // true → 1 (int)20$user3 = new User(true, "Charlie"); // TypeError : Argument 1 must be of type string|int, bool given
Pièges Courants et Bonnes Pratiques
- Héritage de classes : Les sous-classes héritent du mode strict du parent, mais vérifiez les overrides.
- Libraries tierces : Si une lib n'utilise pas strict_types, vos appels peuvent échouer – testez !
- Performance : Négligeable (overhead minime), mais activez-le globalement via un linter.
- Conseil : Adoptez-le fichier par fichier lors de refactorings. Utilisez
composer scriptspour enforcer :vendor/bin/php-cs-fixer fix --rules=declare_strict_types.
En 2025, 80 % des projets pros l'utilisent, selon des sondages Internals. C'est le socle pour exploiter pleinement les nouveautés de PHP 8.4+.
PHP 8.4 : Les Mises à Jour qui Boostent Productivité et Sécurité
Sorti le 21 novembre 2024, PHP 8.4 marque un virage vers plus d'expressivité et de conformité aux standards modernes. Avec un support étendu jusqu'en 2028 (2 ans de bugs + 2 ans de sécurité), c'est une version "maintenance-heavy" mais riche en features. Principales nouveautés : property hooks, visibilité asymétrique, et un DOM HTML5-compliant.
Property Hooks : Adieu Getters/Setters Boilerplate
Inspirés de Kotlin et C#, les property hooks permettent d'attacher du code à l'accès/assignation de propriétés, sans méthodes explicites.
Exemple :
1<?php2class BankAccount {3 protected int $balance = 0;45 public function __get($name) { /* Ancien style */ }6 // Devient :7 public function __get(int $amount): int {8 return $this->balance;9 }1011 public function __set(int $amount): void {12 if ($amount < 0) throw new InvalidArgumentException('Negative balance!');13 $this->balance = $amount;14 $this->logTransaction($amount);15 }16}1718// Usage19$account = new BankAccount();20$account->balance = 100; // Validation + log21echo $account->balance; // Lecture simple1<?php2class BankAccount {3 protected int $balance = 0;45 public function __get($name) { /* Ancien style */ }6 // Devient :7 public function __get(int $amount): int {8 return $this->balance;9 }1011 public function __set(int $amount): void {12 if ($amount < 0) throw new InvalidArgumentException('Negative balance!');13 $this->balance = $amount;14 $this->logTransaction($amount);15 }16}1718// Usage19$account = new BankAccount();20$account->balance = 100; // Validation + log21echo $account->balance; // Lecture simple
Avantage : Moins de code, plus de validation inline. Idéal pour Laravel models.
Visibilité Asymétrique : Lecture Publique, Écriture Privée
Définissez des visibilités différentes pour read/write.
Exemple :
1<?php2class Coffee {3 public private(set) string $flavor = 'Pumpkin Spice';4}56$coffee = new Coffee();7echo $coffee->flavor; // OK : Lecture publique8$coffee->flavor = 'Mocha'; // Fatal error : Cannot modify private property1<?php2class Coffee {3 public private(set) string $flavor = 'Pumpkin Spice';4}56$coffee = new Coffee();7echo $coffee->flavor; // OK : Lecture publique8$coffee->flavor = 'Mocha'; // Fatal error : Cannot modify private property
Parfait pour des configs immuables post-init.
Autres Highlights de PHP 8.4
- DOM API HTML5 : Nouvelles classes
Dom\HTMLDocumentpour parsing compliant, avecquerySelectoretclassList. - BCMath OO :
BCMath\Numberpour ops précises avec opérateurs (+, -, etc.). - Nouvelles Fonctions Array :
array_find_*pour recherches conditionnelles. - Chaining sur
new:new Class()->method()sans parenthèses. - Deprecations :
E_STRICTconstant,CURLOPT_BINARYTRANSFER. Vérifiez viaphp -lvos scripts.
| Fonctionnalité | Impact | Exemple d'Usage |
|---|---|---|
| Property Hooks | -30% boilerplate | Validation DB auto |
| Asym. Visibility | Sécurité accrue | Props immuables |
| DOM HTML5 | Conformité web | Scraping moderne |
| Array Find | Productivité | Cherches conditionnelles |
Performances : +5-10% sur JIT, grâce à des optims GC.
Préparations pour PHP 8.5 : Vers un Typage Encore Plus Expressif
Contexte de la Release
PHP 8.5 sortira le 20 novembre 2025. Actuellement en Release Candidate (version quasi-finale pour tests), cette version ne révolutionne pas le langage mais apporte des améliorations pratiques pour le développement quotidien.
Objectifs principaux :
- Raffiner le système de typage (cohérence avec
strict_types) - Ajouter des opérateurs pour un code plus fluide
- Améliorer l'expérience développeur sans casser la compatibilité
Les Nouvelles Fonctionnalités
1 Fermetures dans les Expressions de Constantes
Qu'est-ce que c'est ? Avant PHP 8.5, vous ne pouviez pas utiliser de fonctions anonymes (closures) dans les valeurs par défaut de constantes ou d'attributs. Maintenant c'est possible !
Exemple simplifié :
1<?php2// AVANT PHP 8.5 ❌ - Impossible3class User {4 public function __construct(5 public array $validators = [fn($x) => $x > 0] // ERREUR !6 ) {}7}89// AVEC PHP 8.5 ✅ - Fonctionne !10#[Attribute]11class Validator {12 public function __construct(13 // Closure comme valeur par défaut14 public array $rules = [fn($value) => strlen($value) > 3]15 ) {}16}1718#[Validator] // Applique automatiquement la validation19class Email {20 public string $address;21}1<?php2// AVANT PHP 8.5 ❌ - Impossible3class User {4 public function __construct(5 public array $validators = [fn($x) => $x > 0] // ERREUR !6 ) {}7}89// AVEC PHP 8.5 ✅ - Fonctionne !10#[Attribute]11class Validator {12 public function __construct(13 // Closure comme valeur par défaut14 public array $rules = [fn($value) => strlen($value) > 3]15 ) {}16}1718#[Validator] // Applique automatiquement la validation19class Email {20 public string $address;21}
Pourquoi c'est utile ?
- Validation dynamique : Définir des règles de validation directement dans les attributs
- Moins de code : Plus besoin de méthodes séparées pour les validations simples
- Type-safe : Avec
strict_types, les types sont vérifiés automatiquement
2 L'Opérateur Pipe (|>)
Qu'est-ce que c'est ? Inspiré de langages fonctionnels comme F#, le pipe permet d'enchaîner des opérations sans créer de variables intermédiaires.
Comment Taper l'Opérateur Pipe | > sur le Clavier : Mémo Rapide
| Système | Clavier | Pipe | |
Chevron > |
Pipe Operator |> |
|---|---|---|---|---|
| Windows | AZERTY | AltGr + 6 | Maj + < | AltGr+6 puis Maj+< |
| Windows | QWERTY | Maj + \ | Maj + . | Maj+\ puis Maj+. |
| macOS | AZERTY | Alt+Maj+L | Maj + < | Alt+Maj+L puis Maj+< |
| macOS | QWERTY | Maj + \ | Maj + . | Maj+\ puis Maj+. |
| Linux | AZERTY | AltGr + 6 | Maj + < | AltGr+6 puis Maj+< |
| Linux | QWERTY | Maj + \ | Maj + > | Maj+\ puis Maj+> |
Exemple détaillé :
1<?php2// ❌ MÉTHODE CLASSIQUE (verbose)3$step1 = strtoupper('hello'); // 'HELLO'4$step2 = substr($step1, 0, 3); // 'HEL'5$result = str_repeat($step2, 2); // 'HELHEL'67// ✅ AVEC PIPE | > (élégant)8$result = 'hello'9 |> strtoupper($$) // $$ = 'hello' → 'HELLO'10 |> substr($$, 0, 3) // $$ = 'HELLO' → 'HEL'11 |> str_repeat($$, 2); // $$ = 'HEL' → 'HELHEL'1<?php2// ❌ MÉTHODE CLASSIQUE (verbose)3$step1 = strtoupper('hello'); // 'HELLO'4$step2 = substr($step1, 0, 3); // 'HEL'5$result = str_repeat($step2, 2); // 'HELHEL'67// ✅ AVEC PIPE | > (élégant)8$result = 'hello'9 |> strtoupper($$) // $$ = 'hello' → 'HELLO'10 |> substr($$, 0, 3) // $$ = 'HELLO' → 'HEL'11 |> str_repeat($$, 2); // $$ = 'HEL' → 'HELHEL'
Cas d'usage réel :
1<?php2// Traitement de données utilisateur3$username = $_POST['username']4 |> trim($$)5 |> strtolower($$)6 |> htmlspecialchars($$)7 |> substr($$, 0, 20);89// Calculs mathématiques10$price = 10011 |> $$ * 1.20 // TVA12 |> round($$, 2) // Arrondi13 |> number_format($$, 2); // Formatage1<?php2// Traitement de données utilisateur3$username = $_POST['username']4 |> trim($$)5 |> strtolower($$)6 |> htmlspecialchars($$)7 |> substr($$, 0, 20);89// Calculs mathématiques10$price = 10011 |> $$ * 1.20 // TVA12 |> round($$, 2) // Arrondi13 |> number_format($$, 2); // Formatage
Avantages :
- Lisibilité : Le flux de transformation est clair (de haut en bas)
- Performance : Pas de variables temporaires en mémoire
- Type-safety : Avec
strict_types, les types se propagent automatiquement
3 Autres Fonctionnalités Importantes
a) Clone With - Copies Partielles
1<?php2class User {3 public function __construct(4 public string $name,5 public string $email,6 public int $age7 ) {}8}91112// ✅ Clone avec modification partielle13$user2 = clone $user1 with {15};1617// Résultat :18// $user1 : Alice, alice@mail.com, 25 (inchangé)19// $user2 : Alice, newemail@mail.com, 25 (email modifié)1<?php2class User {3 public function __construct(4 public string $name,5 public string $email,6 public int $age7 ) {}8}91112// ✅ Clone avec modification partielle13$user2 = clone $user1 with {15};1617// Résultat :
Pourquoi c'est utile ?
- Évite les mutations accidentelles
- Code plus sûr en programmation immutable
- Alternative élégante à la copie manuelle
b) Fonctions Array Natives
1<?php2$numbers = [10, 20, 30, 40, 50];34// ❌ AVANT PHP 8.55$first = reset($numbers); // Modifie le pointeur interne !6$last = end($numbers); // Modifie aussi le pointeur !78// ✅ AVEC PHP 8.59$first = array_first($numbers); // 10 (sans side-effect)10$last = array_last($numbers); // 50 (sans side-effect)1112// Cas d'usage avec types13function getFirstName(array $users): ?string {14 return array_first($users)?->name; // Type-safe avec nullsafe15}1<?php2$numbers = [10, 20, 30, 40, 50];34// ❌ AVANT PHP 8.55$first = reset($numbers); // Modifie le pointeur interne !6$last = end($numbers); // Modifie aussi le pointeur !78// ✅ AVEC PHP 8.59$first = array_first($numbers); // 10 (sans side-effect)10$last = array_last($numbers); // 50 (sans side-effect)1112// Cas d'usage avec types13function getFirstName(array $users): ?string {14 return array_first($users)?->name; // Type-safe avec nullsafe15}
c) Extension URI - Parsing Robuste
1<?php2// Parsing d'URL avec validation45// Validation JSON native améliorée6$data = json_validate_and_decode($jsonString); // Lance une exception si invalide1<?php2// Parsing d'URL avec validation45// Validation JSON native améliorée6$data = json_validate_and_decode($jsonString); // Lance une exception si invalide
d) Deprecations et Migrations
Coercion sur intersections nullables interdite :
1<?php2// ❌ Ne fonctionnera plus3function process(int&null $value) { // Type intersection mal formé4 // ...5}67// ✅ Utiliser plutôt8function process(?int $value) { // Union type standard9 // ...10}1<?php2// ❌ Ne fonctionnera plus3function process(int&null $value) { // Type intersection mal formé4 // ...5}67// ✅ Utiliser plutôt8function process(?int $value) { // Union type standard9 // ...10}
Migration vers Hooks 2.0 :
Les anciennes méthodes magiques (__get, __set) seront progressivement remplacées par des hooks plus performants.
Tableau Récapitulatif
| RFC | Description | Bénéfice avec Strict Types |
|---|---|---|
| Pipe Operator | Chaînage fluide d'opérations | Types inférés automatiquement sans casts manuels |
| Closures in Const | Valeurs par défaut dynamiques | Validation typée à l'exécution |
| Clone With | Copies partielles d'objets | Évite les mutations accidentelles |
| Array First/Last | Accès simplifié aux tableaux | Erreurs de type évitées (pas de side-effects) |
Comment Tester ?
1# Installation de la RC (Release Candidate)2docker pull php:8.5-rc34# Ou compilation manuelle6cd php-src7git checkout PHP-8.58./buildconf && ./configure && make1# Installation de la RC (Release Candidate)2docker pull php:8.5-rc34# Ou compilation manuelle6cd php-src7git checkout PHP-8.58./buildconf && ./configure && make
Testez en environnement de staging avant production !
Pourquoi Migrer Vers Strict Types et PHP 8.x ?
- Sécurité : Moins de vulnérabilités type confusion.
- Perf : Typage strict + JIT = apps 20% plus rapides.
- Écosystème : Laravel 12, Symfony 7 exploitent ces features.
- Plan d'Action :
- Activez strict_types globalement (via .php_cs).
- Upgradez à 8.4 :
phpbrew install 8.4. - Testez 8.5 RC : Suivez php.net/downloads.
PHP n'est plus "le langage des scripts sales" – c'est un pilier enterprise. Avec 8.4 en prod et 8.5 imminent, 2025 est l'année du typage maître.
À vous : Implémentez un hook en 8.4 et testez le pipe en RC. Le futur est typed !
En Résumé
PHP 8.5 est une version d'amélioration progressive qui :
- Rend le code plus expressif (pipe, closures)
- Améliore la sécurité des types (strict_types mieux intégré)
- Simplifie les opérations courantes (array_first/last, clone with)
Sources : RFCs PHP.net, annonces officielles, blogs Stitcher.io et PHP.Watch.