1. Accueil
  2. Articles
9 min de lecture
470 vues

PHP : Maîtriser les Types Strict, les Nouveautés de PHP 8.4 et les Préparatifs pour PHP 8.5

Image d'illustration pour PHP : Maîtriser les Types Strict, les Nouveautés de PHP 8.4 et les Préparatifs pour PHP 8.5

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 TypeError au 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<?php
2function addition(int $a, int $b): int {
3 return $a + $b;
4}
5 
6echo addition('5', 3); // Affiche 8 (conversion '5' → 5)
1<?php
2function addition(int $a, int $b): int {
3 return $a + $b;
4}
5 
6echo addition('5', 3); // Affiche 8 (conversion '5' → 5)

Avec strict_types (typage strict) :

1<?php
2declare(strict_types=1);
3 
4function addition(int $a, int $b): int {
5 return $a + $b;
6}
7 
8echo addition('5', 3); // TypeError: Argument 1 must be of type int, string given
1<?php
2declare(strict_types=1);
3 
4function addition(int $a, int $b): int {
5 return $a + $b;
6}
7 
8echo 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<?php
2declare(strict_types=1);
3 
4class User {
5 public function __construct(
6 public readonly string|int $id, // Union type (PHP 8.0+)
7 public string $name
8 ) {}
9 
10 public function greet(): string {
11 return "Hello, {$this->name}! ID: {$this->id}";
12 }
13}
14 
15// Usage
16$user = new User(123, "Alice"); // OK : int pour id
17$user2 = new User("user-456", "Bob"); // OK : string pour id
18 
19// 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
1<?php
2declare(strict_types=1);
3 
4class User {
5 public function __construct(
6 public readonly string|int $id, // Union type (PHP 8.0+)
7 public string $name
8 ) {}
9 
10 public function greet(): string {
11 return "Hello, {$this->name}! ID: {$this->id}";
12 }
13}
14 
15// Usage
16$user = new User(123, "Alice"); // OK : int pour id
17$user2 = new User("user-456", "Bob"); // OK : string pour id
18 
19// 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 scripts pour 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<?php
2class BankAccount {
3 protected int $balance = 0;
4 
5 public function __get($name) { /* Ancien style */ }
6 // Devient :
7 public function __get(int $amount): int {
8 return $this->balance;
9 }
10 
11 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}
17 
18// Usage
19$account = new BankAccount();
20$account->balance = 100; // Validation + log
21echo $account->balance; // Lecture simple
1<?php
2class BankAccount {
3 protected int $balance = 0;
4 
5 public function __get($name) { /* Ancien style */ }
6 // Devient :
7 public function __get(int $amount): int {
8 return $this->balance;
9 }
10 
11 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}
17 
18// Usage
19$account = new BankAccount();
20$account->balance = 100; // Validation + log
21echo $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<?php
2class Coffee {
3 public private(set) string $flavor = 'Pumpkin Spice';
4}
5 
6$coffee = new Coffee();
7echo $coffee->flavor; // OK : Lecture publique
8$coffee->flavor = 'Mocha'; // Fatal error : Cannot modify private property
1<?php
2class Coffee {
3 public private(set) string $flavor = 'Pumpkin Spice';
4}
5 
6$coffee = new Coffee();
7echo $coffee->flavor; // OK : Lecture publique
8$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\HTMLDocument pour parsing compliant, avec querySelector et classList.
  • BCMath OO : BCMath\Number pour 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_STRICT constant, CURLOPT_BINARYTRANSFER. Vérifiez via php -l vos 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<?php
2// AVANT PHP 8.5 ❌ - Impossible
3class User {
4 public function __construct(
5 public array $validators = [fn($x) => $x > 0] // ERREUR !
6 ) {}
7}
8 
9// AVEC PHP 8.5 ✅ - Fonctionne !
10#[Attribute]
11class Validator {
12 public function __construct(
13 // Closure comme valeur par défaut
14 public array $rules = [fn($value) => strlen($value) > 3]
15 ) {}
16}
17 
18#[Validator] // Applique automatiquement la validation
19class Email {
20 public string $address;
21}
1<?php
2// AVANT PHP 8.5 ❌ - Impossible
3class User {
4 public function __construct(
5 public array $validators = [fn($x) => $x > 0] // ERREUR !
6 ) {}
7}
8 
9// AVEC PHP 8.5 ✅ - Fonctionne !
10#[Attribute]
11class Validator {
12 public function __construct(
13 // Closure comme valeur par défaut
14 public array $rules = [fn($value) => strlen($value) > 3]
15 ) {}
16}
17 
18#[Validator] // Applique automatiquement la validation
19class 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<?php
2// ❌ MÉTHODE CLASSIQUE (verbose)
3$step1 = strtoupper('hello'); // 'HELLO'
4$step2 = substr($step1, 0, 3); // 'HEL'
5$result = str_repeat($step2, 2); // 'HELHEL'
6 
7// ✅ AVEC PIPE | > (élégant)
8$result = 'hello'
9 |> strtoupper($$) // $$ = 'hello' → 'HELLO'
10 |> substr($$, 0, 3) // $$ = 'HELLO' → 'HEL'
11 |> str_repeat($$, 2); // $$ = 'HEL' → 'HELHEL'
1<?php
2// ❌ MÉTHODE CLASSIQUE (verbose)
3$step1 = strtoupper('hello'); // 'HELLO'
4$step2 = substr($step1, 0, 3); // 'HEL'
5$result = str_repeat($step2, 2); // 'HELHEL'
6 
7// ✅ 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<?php
2// Traitement de données utilisateur
3$username = $_POST['username']
4 |> trim($$)
5 |> strtolower($$)
6 |> htmlspecialchars($$)
7 |> substr($$, 0, 20);
8 
9// Calculs mathématiques
10$price = 100
11 |> $$ * 1.20 // TVA
12 |> round($$, 2) // Arrondi
13 |> number_format($$, 2); // Formatage
1<?php
2// Traitement de données utilisateur
3$username = $_POST['username']
4 |> trim($$)
5 |> strtolower($$)
6 |> htmlspecialchars($$)
7 |> substr($$, 0, 20);
8 
9// Calculs mathématiques
10$price = 100
11 |> $$ * 1.20 // TVA
12 |> round($$, 2) // Arrondi
13 |> 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<?php
2class User {
3 public function __construct(
4 public string $name,
5 public string $email,
6 public int $age
7 ) {}
8}
9 
10$user1 = new User('Alice', 'alice@mail.com', 25);
11 
12// ✅ Clone avec modification partielle
13$user2 = clone $user1 with {
14 $email = 'newemail@mail.com' // Change seulement l'email
15};
16 
17// Résultat :
18// $user1 : Alice, alice@mail.com, 25 (inchangé)
19// $user2 : Alice, newemail@mail.com, 25 (email modifié)
1<?php
2class User {
3 public function __construct(
4 public string $name,
5 public string $email,
6 public int $age
7 ) {}
8}
9 
10$user1 = new User('Alice', 'alice@mail.com', 25);
11 
12// ✅ Clone avec modification partielle
13$user2 = clone $user1 with {
14 $email = 'newemail@mail.com' // Change seulement l'email
15};
16 
17// Résultat :
18// $user1 : Alice, alice@mail.com, 25 (inchangé)
19// $user2 : Alice, newemail@mail.com, 25 (email modifié)

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<?php
2$numbers = [10, 20, 30, 40, 50];
3 
4// ❌ AVANT PHP 8.5
5$first = reset($numbers); // Modifie le pointeur interne !
6$last = end($numbers); // Modifie aussi le pointeur !
7 
8// ✅ AVEC PHP 8.5
9$first = array_first($numbers); // 10 (sans side-effect)
10$last = array_last($numbers); // 50 (sans side-effect)
11 
12// Cas d'usage avec types
13function getFirstName(array $users): ?string {
14 return array_first($users)?->name; // Type-safe avec nullsafe
15}
1<?php
2$numbers = [10, 20, 30, 40, 50];
3 
4// ❌ AVANT PHP 8.5
5$first = reset($numbers); // Modifie le pointeur interne !
6$last = end($numbers); // Modifie aussi le pointeur !
7 
8// ✅ AVEC PHP 8.5
9$first = array_first($numbers); // 10 (sans side-effect)
10$last = array_last($numbers); // 50 (sans side-effect)
11 
12// Cas d'usage avec types
13function getFirstName(array $users): ?string {
14 return array_first($users)?->name; // Type-safe avec nullsafe
15}

c) Extension URI - Parsing Robuste

1<?php
2// Parsing d'URL avec validation
4 
5// Validation JSON native améliorée
6$data = json_validate_and_decode($jsonString); // Lance une exception si invalide
1<?php
2// Parsing d'URL avec validation
4 
5// Validation JSON native améliorée
6$data = json_validate_and_decode($jsonString); // Lance une exception si invalide

d) Deprecations et Migrations

Coercion sur intersections nullables interdite :

1<?php
2// ❌ Ne fonctionnera plus
3function process(int&null $value) { // Type intersection mal formé
4 // ...
5}
6 
7// ✅ Utiliser plutôt
8function process(?int $value) { // Union type standard
9 // ...
10}
1<?php
2// ❌ Ne fonctionnera plus
3function process(int&null $value) { // Type intersection mal formé
4 // ...
5}
6 
7// ✅ Utiliser plutôt
8function process(?int $value) { // Union type standard
9 // ...
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-rc
3 
4# Ou compilation manuelle
6cd php-src
7git checkout PHP-8.5
8./buildconf && ./configure && make
1# Installation de la RC (Release Candidate)
2docker pull php:8.5-rc
3 
4# Ou compilation manuelle
6cd php-src
7git checkout PHP-8.5
8./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 :
    1. Activez strict_types globalement (via .php_cs).
    2. Upgradez à 8.4 : phpbrew install 8.4.
    3. 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.