Mis à jour ces 90 derniers jours 16 nouvelles · 7 révisées
Attribut natif de PHP 8.4 qui marque une fonction, une méthode, une constante de classe ou un cas d'enum comme déprécié. À l'appel, le moteur émet un E_USER_DEPRECATED avec le message et la version (since) fournis ; la réflexion expose isDeprecated().
L'étiquette « bientôt retiré de la vente » sur un produit encore en rayon.
class PhpVersion
{
#[\Deprecated(
message: "utilisez getVersion() à la place",
since: "8.4",
)]
public function getPhpVersion(): string
{
return $this->getVersion();
}
}
// Appel : Deprecated: Method PhpVersion::getPhpVersion()
// is deprecated since 8.4, utilisez getVersion() à la placeCas d'usage : Faire évoluer une API publique de bibliothèque sans casser les utilisateurs, avec un signal uniforme pour les IDE et l'analyse statique.
Attribut de PHP 8.5 qui avertit (E_WARNING pour les fonctions natives, E_USER_WARNING pour le code utilisateur) quand la valeur de retour d'une fonction est ignorée. Le cast (void) marque un rejet volontaire. Appliqué nativement à flock() et aux méthodes set*() de DateTimeImmutable.
Le distributeur qui bipe si vous partez sans prendre votre carte.
#[\NoDiscard]
function getPhpVersion(): string {
return 'PHP 8.5';
}
getPhpVersion();
// Warning: The return value should either be used
// or intentionally ignored
(void) getPhpVersion(); // rejet explicite, pas d'avertissement
// piège classique désormais signalé :
$date->setTime(0, 0); // DateTimeImmutable retourne une copie !Cas d'usage : Objets immuables (with*/set* qui retournent une copie) et fonctions dont le retour porte un statut à vérifier.
Attribut de PHP 8.3 qui déclare qu'une méthode surcharge une méthode parente ou d'interface. Si aucune méthode correspondante n'existe (faute de frappe, renommage dans la classe mère), PHP lève une erreur fatale à la compilation au lieu de laisser une méthode orpheline silencieuse.
Le « répondre à » d'un courriel : si le message d'origine n'existe pas, la messagerie refuse d'envoyer.
class MyTest extends TestCase
{
#[\Override]
protected function taerDown(): void
{
// Fatal error: MyTest::taerDown() has #[\Override]
// attribute, but no matching parent method exists
}
}Cas d'usage : Tests, hooks de framework et hiérarchies profondes : sécuriser les refactorisations de la classe mère.
Classe qui ne peut pas être instanciee directement et qui sert de modèle. Elle peut contenir des méthodes abstraites (sans corps) et des méthodes concrètes.
Comme un plan d'architecte : il définit la structure mais on ne peut pas y habiter, il faut d'abord construire la maison.
abstract class Shape {
abstract public function area(): float;
public function describe(): string {
return get_class($this) . ': ' . $this->area();
}
}Cas d'usage : Quand plusieurs classes partagent une logique commune mais doivent chacune implémenter certains comportements spécifiques.
Pattern qui fournit une interface pour créer des familles d'objets lies sans spécifier leurs classes concrètes. Étend le Factory Method a plusieurs produits.
Comme un concessionnaire de marque : Peugeot produit berlines ET SUV, Toyota aussi, mais dans leur propre style.
interface UIFactory {
public function createButton(): Button;
public function createInput(): Input;
}
class DarkThemeFactory implements UIFactory {
public function createButton(): Button { return new DarkButton(); }
public function createInput(): Input { return new DarkInput(); }
}Cas d'usage : Quand on doit créer des familles d'objets cohérents (theme UI, drivers de base de données).
Deux patterns ORM opposes. Active Record (Éloquent) : l'objet connaît sa persistence. Data Mapper (Doctrine) : un mapper externe gère la persistence, l'entité reste pure.
Active Record : un employé qui classe lui-même ses dossiers. Data Mapper : un archiviste indépendant qui gère le classement.
// Active Record (Eloquent)
$user = User::find(1);
$user->name = 'Alice';
$user->save();
// Data Mapper (Doctrine)
$user = $em->find(User::class, 1);
$user->setName('Alice');
$em->flush();Cas d'usage : Active Record pour les projets simples/rapides, Data Mapper pour les domaines complexes avec logique métier riche.
Classes sans nom définies a la volée avec new class. Utiles pour créer des implémentations jetables d'interfaces, surtout dans les tests.
Comme un figurant dans un film : il joue son role une seule fois sans avoir besoin d'un nom au générique.
$mock = new class implements Logger {
public array $logs = [];
public function log(string $msg): void {
$this->logs[] = $msg;
}
};Cas d'usage : Pour les tests unitaires (mocks rapides) ou les implémentations uniques dans des factories.
Fonctions ajoutées en PHP 8.4 : array_find() retourne la première valeur qui satisfait un callback (null sinon), array_find_key() sa clé, array_any() et array_all() testent l'existence ou l'universalité. Elles évitent le duo array_filter + reset.
Chercher la première chaussette rouge dans le tiroir et s'arrêter dès qu'on la trouve.
$animals = ['dog', 'cat', 'cow', 'duck', 'goose'];
$first = array_find(
$animals,
static fn(string $v): bool => str_starts_with($v, 'c'),
); // 'cat'
$key = array_find_key($animals, fn($v) => $v === 'duck'); // 3
$any = array_any($animals, fn($v) => strlen($v) > 4); // true
$all = array_all($animals, fn($v) => strlen($v) >= 3); // trueCas d'usage : Recherche du premier élément correspondant, vérifications « au moins un » / « tous » sans boucle manuelle.
Syntaxe courte fn() => pour les closures a une seule expression, avec capture automatique des variables du scope parent par valeur.
Comme un post-it avec une instruction rapide au lieu d'écrire une lettre complète.
$prices = [10, 20, 30];
$tax = 0.2;
$withTax = array_map(
fn($price) => $price * (1 + $tax),
$prices
);Cas d'usage : Pour les callbacks courts dans array_map, array_filter et autres fonctions d'ordre supérieur.
Métadonnées structurées ajoutées au code via #[...], introduites en PHP 8.0. Elles remplacent les annotations en commentaires par une syntaxe native. Le langage fournit désormais ses propres attributs : #[\Override] (PHP 8.3), #[\Deprecated] (PHP 8.4) et #[\NoDiscard] (PHP 8.5).
Comme des étiquettes collées sur des boites : elles décrivent le contenu sans le modifier.
#[Route('/api/users', methods: ['GET'])]
class UserController {
#[Cache(ttl: 3600)]
public function list(): Response {
// ...
}
}Cas d'usage : Configuration déclarative (routes, validation, mapping ORM) et signaux au moteur ou aux outils : méthode surchargée, fonction dépréciée, valeur de retour à ne pas ignorer.
Depuis PHP 8.5, clone accepte un second argument : un tableau de propriétés à modifier sur la copie, clone($obj, ['prop' => $v]). Les propriétés readonly y sont modifiables, ce qui permet les méthodes withX() des objets-valeur immuables. __clone() s'exécute avant l'affectation des nouvelles valeurs.
Photocopier un formulaire rempli et corriger une seule case sur la copie.
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]);
}
}
$c = new Color(255, 0, 0)->withAlpha(128);Cas d'usage : Objets-valeur et DTO immuables : dériver une variante sans réécrire le constructeur ni contourner readonly par réflexion.
Gestionnaire de dépendances standard de PHP. Il gère les paquets, l'autoloading PSR-4, les scripts et le versionnement sémantique via composer.json. Composer 2.0 (24 octobre 2020) a apporté les téléchargements parallèles, la vérification de plateforme au chargement et l'API Composer\InstalledVersions.
Comme un chef de chantier qui commande les bons matériaux dans les bonnes versions et s'assure que tout est compatible.
{
"require": {
"php": "^8.4",
"laravel/framework": "^12.0"
},
"autoload": {
"psr-4": { "App\\": "src/" }
}
}Cas d'usage : Dans tout projet PHP moderne pour gérer les dépendances et l'autoloading.
Principe de design qui favorise l'assemblage d'objets (a un) plutôt que l'héritage (est un) pour la réutilisation de code. Produit des architectures plus flexibles.
Comme des briques LEGO : on assemble des pièces pour construire ce qu'on veut, plutôt que d'hériter d'un modèle fixe.
class OrderService {
public function __construct(
private PaymentGateway $payment,
private Mailer $mailer,
private Logger $logger,
) {}
}Cas d'usage : Dans la majorité des cas ou on est tente d'hériter pour réutiliser du code.
Syntaxe PHP 8.0 qui déclare et assigne les propriétés directement dans la signature du constructeur, éliminant le code répétitif.
Comme remplir un formulaire qui crée automatiquement le dossier, au lieu de recopier chaque champ a la main.
class Product {
public function __construct(
private string $name,
private float $price,
private int $stock = 0,
) {}
}Cas d'usage : Pour tout constructeur PHP : réduit le boilerplate et rend le code plus lisible.
Attaque qui force un utilisateur authentifie a exécuter des actions non voulues sur un site ou il est connecte, via un lien ou formulaire piège.
Comme quelqu'un qui imite ta signature pour envoyer une lettre en ton nom.
// Generation du token
$_SESSION['csrf'] = bin2hex(random_bytes(32));
echo '<input type="hidden" name="csrf" value="'
. $_SESSION['csrf'] . '">';
// Verification
if (!hash_equals($_SESSION['csrf'], $_POST['csrf']))
throw new SecurityException();Cas d'usage : Sur tout formulaire ou action modifiant des données (POST, PUT, DELETE).
Repères à connaître en entretien (relevés le 27/09/2026). Symfony : 8.1 stable (mai 2026, PHP ≥ 8.4), 7.4 LTS (novembre 2025, corrections jusqu'en novembre 2028), 8.2 attendue en novembre 2026. Laravel : une majeure par an vers le T1 ; Laravel 12 (24 février 2025, PHP 8.2 à 8.5) reçoit des correctifs de bugs jusqu'au 13 août 2026, Laravel 13 est la version courante.
Le calendrier des soldes : savoir quand la prochaine collection arrive évite d'acheter la veille.
{
"require": {
"php": "^8.4",
"symfony/framework-bundle": "^7.4",
"_commentaire": "7.4 = LTS jusqu'en 11/2028 ; 8.x = dernières fonctionnalités"
}
}Cas d'usage : Choisir entre LTS et dernière majeure pour un projet client, et argumenter une migration PHP (Symfony 8 impose PHP 8.4).
Les modules de haut niveau ne doivent pas dépendre de modules de bas niveau. Les deux doivent dépendre d'abstractions (interfaces). L'abstraction ne dépend pas des détails.
Comme un chef qui commande 'du poisson frais' sans se soucier du fournisseur spécifique.
// Haut niveau depend de l'abstraction
class OrderService {
public function __construct(
private PaymentGateway $gateway // interface
) {}
}
// Bas niveau implemente l'abstraction
class StripePayment implements PaymentGateway { }Cas d'usage : Pour découvrir les couches de l'application et permettre le remplacement des implémentations (tests, refactoring).
Container d'injection de dépendances qui instancie automatiquement les objets et leurs dépendances. Réalisation concrète du principe d'inversion de dépendances.
Comme une agence d'intérim : tu décris le profil recherche, elle fournit la personne qualifiée.
// Symfony DI
services:
App\Service\Mailer:
arguments:
$transport: '@mailer.transport'
// Auto-wiring resout les types automatiquementCas d'usage : Pour éliminer les new manuels et centraliser la configuration des services.
Nouvelle API DOM de PHP 8.4, dans l'espace de noms Dom, conforme aux standards et dotée d'un vrai parseur HTML5. Dom\HTMLDocument::createFromString()/createFromFile() remplacent DOMDocument (parseur XML) et offrent querySelector(), classList et un encodage UTF-8 par défaut.
Passer d'un traducteur qui ne comprend que le latin classique à un natif qui lit l'argot d'aujourd'hui.
$dom = Dom\HTMLDocument::createFromString(
'<main><article>PHP 8.4</article>
<article class="featured">DOM HTML5</article></main>',
LIBXML_NOERROR,
);
$node = $dom->querySelector('main > article:last-child');
var_dump($node->classList->contains('featured')); // true
// avant : new DOMDocument() + loadHTML() + DOMXPathCas d'usage : Scraper ou nettoyer du HTML réel (balises non fermées, HTML5) sans les avertissements et les erreurs de DOMDocument.
Principe OOP qui restreint l'accès direct aux données internes d'un objet via des modificateurs de visibilité (public, protected, private).
Comme un distributeur de billets : tu interagis via l'écran et le clavier, pas en ouvrant le coffre.
class BankAccount {
private float $balance = 0;
public function deposit(float $amount): void {
if ($amount <= 0) throw new \InvalidArgumentException();
$this->balance += $amount;
}
public function getBalance(): float { return $this->balance; }
}Cas d'usage : Pour protéger l'état interne des objets et garantir que les modifications passent par des méthodes contrôlées.
Type introduit en PHP 8.1 qui représente un ensemble fini de valeurs possibles. Les enums peuvent être pures ou « backed » (avec valeur string ou int). Depuis PHP 8.4, un cas peut être marqué #[\Deprecated] pour signaler son retrait futur.
Comme les feux de signalisation : il n'existe que rouge, orange et vert, rien d'autre.
enum Status: string {
case Draft = 'draft';
case Published = 'published';
case Archived = 'archived';
}
$post->status = Status::Published;Cas d'usage : Pour remplacer les constantes de classe et garantir qu'une valeur appartient à un ensemble défini.
Extension intégrée à PHP 8.5 qui analyse les URI selon deux normes : Uri\Rfc3986\Uri (générique) et Uri\WhatWg\Url (comportement navigateur). Classes finales et immuables, méthodes with*() et résolution de références relatives. Elle corrige parse_url(), non conforme à un standard et source de confusions exploitables.
Un lecteur de codes-barres officiel à la place d'un employé qui lit l'étiquette à l'œil.
use Uri\Rfc3986\Uri;
use Uri\WhatWg\Url;
$uri = new Uri('https://php.net/releases/8.5/en.php');
var_dump($uri->getHost()); // "php.net"
$copy = $uri->withScheme('http')->withPath('/docs');
echo $copy->toString();
// hôtes Unicode côté WHATWG
$url = new Url('https://exämple.com/');
echo $url->getAsciiHost(); // punycode
echo $url->getUnicodeHost(); // exämple.comCas d'usage : Valider une URL soumise par l'utilisateur, normaliser des liens, résoudre une référence relative comme le ferait un navigateur.
Pattern de création qui délègué l'instanciation d'objets a une méthode ou classe dédiée, plutôt que d'appeler new directement.
Comme une commande au restaurant : tu choisis le plat, la cuisine décidé comment le préparer.
class NotificationFactory {
public static function create(string $type): Notifier {
return match($type) {
'email' => new EmailNotifier(),
'sms' => new SmsNotifier(),
'push' => new PushNotifier(),
};
}
}Cas d'usage : Pour centraliser la logique de création et découpler le code appelant des classes concrètes.
Primitive de concurrence introduite en PHP 8.1 permettant de suspendre et reprendre l'exécution d'un bloc de code. Base des frameworks asynchrones comme Revolt.
Comme mettre un livre en pause avec un marque-page pour en lire un autre, puis reprendre exactement ou on s'était arrêté.
$fiber = new Fiber(function (): void {
$value = Fiber::suspend('paused');
echo "Repris avec: $value";
});
$result = $fiber->start(); // 'paused'
$fiber->resume('hello');Cas d'usage : Pour construire des bibliothèques asynchrones ou des event loops sans callbacks imbriques.
Mécanisme OOP permettant a une classe enfant d'hériter des propriétés et méthodes d'une classe parente. PHP ne supporte que l'héritage simple.
Comme un enfant qui hérite des caractéristiques de ses parents mais peut développer les siennes.
class Animal {
public function breathe(): string { return 'respire'; }
}
class Dog extends Animal {
public function bark(): string { return 'wouf'; }
}
// Dog peut breathe() ET bark()Cas d'usage : Quand il existe une vraie relation 'est un' entre deux classes (un Chien EST un Animal).
Vérification systématique des données entrantes (formulaires, API, fichiers) contre un format attendu. Première ligne de défense contre les attaques.
Comme le contrôle de sécurité a l'aéroport : on vérifie tout ce qui entre avant de laisser passer.
$email = filter_input(
INPUT_POST, 'email', FILTER_VALIDATE_EMAIL
);
if ($email === false) {
throw new ValidationException('Email invalide');
}Cas d'usage : A chaque point d'entrée de données externes : formulaires, API, imports de fichiers.
Contrat qui définit les méthodes qu'une classe doit implémenter, sans fournir d'implémentation. Permet le polymorphisme et le decouplage.
Comme une prise électrique standard : tout appareil qui respecte le format peut se brancher.
interface PaymentGateway {
public function charge(float $amount): bool;
public function refund(string $txId): bool;
}
class StripeGateway implements PaymentGateway {
public function charge(float $amount): bool { /* ... */ }
public function refund(string $txId): bool { /* ... */ }
}Cas d'usage : Pour définir des contrats entre composants et permettre de changer d'implémentation sans modifier le code appelant.
Les clients ne doivent pas être forces d'implémenter des interfaces qu'ils n'utilisent pas. Privilégier plusieurs petites interfaces a une grande interface générâle.
Comme un menu a la carte vs un menu fixe : on choisit uniquement ce qu'on veut manger.
// Mauvais: interface grasse
// interface Worker { work(); eat(); sleep(); }
// Bon: interfaces segregees
interface Workable { public function work(): void; }
interface Feedable { public function eat(): void; }
class Robot implements Workable {
public function work(): void { /* ... */ }
}Cas d'usage : Quand différentes classes n'ont besoin que d'un sous-ensemble du comportement d'une interface.
Compilation Just-In-Time ajoutée en PHP 8.0 qui compile le bytecode en code machine natif à l'exécution. PHP 8.4 (21 novembre 2024) a remplacé l'implémentation d'origine par un nouveau JIT fondé sur le framework IR. Le gain reste surtout visible sur les tâches CPU-intensives.
Comme un traducteur simultané qui finit par parler directement dans la langue cible sans passer par la traduction.
; php.ini
opcache.jit=1255
opcache.jit_buffer_size=256MCas d'usage : Pour les applications CPU-bound (calculs, traitement d'images). Peu d'impact sur les apps web classiques IO-bound.
Mécanisme (static:: vs self::) qui résout la référence a la classe au moment de l'exécution, pas de la définition. Permet aux méthodes héritées de référencer la classe enfant.
Comme un formulaire générique qui s'adapte au logo de l'entreprise qui l'utilise, pas celle qui l'a créé.
class Model {
public static function create(array $data): static {
return new static($data); // static = classe enfant
}
}
class User extends Model {}
$user = User::create(['name' => 'Alice']); // retourne UserCas d'usage : Dans les classes de base (ORM, factories) ou les méthodes héritées doivent retourner le type de la sous-classe.
Objets PHP 8.4 dont l'initialisation est différée jusqu'au premier accès à leur état. Deux stratégies via ReflectionClass : newLazyGhost() initialise l'objet sur place, newLazyProxy() délègué à une instance réelle créée à la demande. Lecture, écriture, clonage ou sérialisation déclenchent l'initialisation.
Une chambre d'hôtel qu'on ne prépare que quand un client ouvre la porte.
class Report {
public function __construct(public array $rows) {
echo "chargement coûteux\n";
}
}
$rc = new ReflectionClass(Report::class);
$lazy = $rc->newLazyGhost(function (Report $r) {
$r->__construct(fetchRows()); // exécuté au 1er accès
});
// rien n'est encore chargé
echo count($lazy->rows); // déclenche l'initialisationCas d'usage : Conteneurs d'injection (services lourds jamais appelés) et ORM (entités hydratées à la demande), sans proxys générés.
Toute instance d'une classe parente doit pouvoir être remplacée par une instance de classe enfant sans casser le programme. Les sous-types doivent respecter le contrat du parent.
Comme un remplaçant au football : il doit pouvoir jouer au même poste sans changer les règles du jeu.
class Rectangle {
public function setWidth(int $w): void { $this->w = $w; }
public function setHeight(int $h): void { $this->h = $h; }
public function area(): int { return $this->w * $this->h; }
}
// Square qui override setWidth/setHeight viole LSP
// car le comportement change de facon inattendueCas d'usage : Lors de la conception de hiérarchies d'héritage pour éviter les bugs subtils lies aux sous-classes.
Méthodes spéciales prefixees par __ (__construct, __get, __set, __toString, etc.) appelées automatiquement par PHP dans certaines situations.
Comme les réflexes du corps : ils se déclenchent automatiquement en réaction a un stimulus, sans y penser.
class Config {
private array $data = [];
public function __get(string $key): mixed {
return $this->data[$key] ?? null;
}
public function __set(string $key, mixed $val): void {
$this->data[$key] = $val;
}
}Cas d'usage : Pour créer des APIs fluides, du lazy loading ou des wrappers dynamiques.
Expression PHP 8.0 similaire a switch mais avec comparaison stricte, pas de fall-through, et qui retourne une valeur. Plus sure et concise que switch.
Comme un distributeur automatique : tu inseres le code exact, tu reçois le produit correspondant, pas d'ambiguïté.
$label = match($status) {
'draft' => 'Brouillon',
'published' => 'Publie',
'archived' => 'Archive',
default => 'Inconnu',
};Cas d'usage : Pour remplacer les switch/case simples qui retournent une valeur en fonction d'une condition.
Fonctions multi-octets ajoutées en PHP 8.4 : mb_trim(), mb_ltrim(), mb_rtrim(), mb_ucfirst(), mb_lcfirst(). mb_trim() retire par défaut les espaces Unicode (espace insécâble U+00A0, espace idéographique U+3000, séparateurs de ligne…), là où trim() ne connaît que les espaces ASCII.
Un aspirateur qui ramasse aussi la poussière invisible, pas seulement les miettes.
$s = "\u{00A0}Bonjour\u{3000}";
var_dump(trim($s) === $s); // true : trim() ne voit rien
var_dump(mb_trim($s)); // "Bonjour"
// signature
// mb_trim(string $string, ?string $characters = null,
// ?string $encoding = null): string
echo mb_ucfirst('éléphant'); // ÉléphantCas d'usage : Nettoyer des saisies copiées-collées depuis Word, des exports ou des contenus multilingues avant validation ou comparaison.
Pattern architectural séparant Model (données/logique), View (affichage) et Controller (orchestration). Base de la majorité des frameworks PHP.
Comme un restaurant : le cuisinier (Model), la présentation du plat (View), le serveur (Controller) qui coordonne.
class UserController {
public function show(int $id): Response {
$user = $this->userRepo->find($id); // Model
return $this->render('user/show', [
'user' => $user // View
]);
}
}Cas d'usage : Structure de base pour toute application web PHP avec séparation des responsabilités.
Fonctionnalité PHP 8.0 permettant de passer des arguments par nom plutôt que par position. Amélioré la lisibilité et permet de sauter les paramètrès optionnels.
Comme remplir un formulaire ou chaque champ a une étiquette, au lieu de deviner l'ordre des cases.
function createUser(
string $name,
string $email,
string $role = 'user'
): User { /* ... */ }
createUser(name: 'Alice', email: '[email protected]');Cas d'usage : Pour les fonctions avec beaucoup de paramètrès optionnels, ou la lisibilité est cruciale.
Espace de noms qui organise le code en groupes logiques et évite les collisions de noms entre classes. Introduit en PHP 5.3, c'est la base de l'autoloading moderne.
Comme les noms de famille : deux personnes peuvent s'appeler Marie, mais Marie Dupont et Marie Martin sont distinctes.
namespace App\Services;
use App\Models\User;
class UserService {
public function find(int $id): User {
return User::findOrFail($id);
}
}Cas d'usage : Dans tout projet PHP moderne pour organiser le code et permettre l'autoloading PSR-4 via Composer.
Depuis PHP 8.4, on peut chaîner un appel directement sur une instanciation : new Foo()->bar() sans envelopper new Foo() dans des parenthèses. La RFC a été adoptée 25 voix contre 4. La condition : écrire les parenthèses du constructeur ; (new Foo)->bar reste nécessaire sinon.
Ouvrir une boîte et prendre l'objet dedans dans le même geste, au lieu de la poser d'abord sur la table.
// PHP 8.4
$req = new Request()->withMethod('GET')->withUri('/hello');
// Avant : parenthèses obligatoires
$req = (new Request())->withMethod('GET');
// Toujours interdit sans () du constructeur :
// new Request->withMethod('GET');Cas d'usage : Alléger les builders et objets fluents (requêtes HTTP, configurateurs) instanciés puis configurés d'un trait.
Opérateur ?-> de PHP 8.0 qui court-circuite la chaîne d'appels si une valeur intermédiaire est null, retournant null au lieu de lancer une erreur.
Comme un GPS qui s'arrête de calculer l'itinéraire si la destination n'existe pas, au lieu de planter.
// Avant
$country = $user->getAddress()
? $user->getAddress()->getCountry()
: null;
// Apres
$country = $user?->getAddress()?->getCountry();Cas d'usage : Pour naviguer dans des chaînés d'objets potentiellement null sans multiples vérifications if/null.
Pattern ou un sujet notifie automatiquement ses observateurs quand son état change. Base du système d'evenements en PHP et du Hook System WordPress.
Comme une chaîne YouTube : quand une vidéo est publiée, tous les abonnes sont notifies automatiquement.
interface Observer {
public function update(Event $event): void;
}
class EventDispatcher {
public function dispatch(Event $event): void {
foreach ($this->listeners[$event::class] as $listener) {
$listener->update($event);
}
}
}Cas d'usage : Pour découpler les actions : après la création d'un compte, envoyer un email, créer un log, notifier l'admin.
Extension native qui met en cache le bytecode compile des scripts PHP en mémoire partagée, éliminant la recompilation a chaque requête. Gain de 30-70% de performance.
Comme mémoriser une recette au lieu de la relire a chaque fois qu'on cuisine le même plat.
; php.ini
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0 ; prod onlyCas d'usage : Obligatoire en production, c'est le premier levier de performance PHP.
Les entités logicielles doivent être ouvertes a l'extension mais fermées a la modification. On ajoute du comportement sans toucher au code existant.
Comme une multiprise : on peut brancher de nouveaux appareils sans modifier l'installation électrique.
interface Discount {
public function calculate(float $price): float;
}
class StudentDiscount implements Discount {
public function calculate(float $price): float {
return $price * 0.8;
}
}
// Ajout sans modifier le code existantCas d'usage : Quand un système doit évoluer fréquemment : nouveaux types de paiement, nouvelles règles métier.
Opérateur de PHP 8.5 (20 novembre 2025) qui passe la valeur de gauche comme unique argument au callable de droite, en chaîne de gauche à droite. La RFC a été adoptée 33 voix contre 7. Il se combine avec la syntaxe de callable de première classe (trim(...)) et refuse les paramètrès par référence.
Une chaîne de montage : la pièce passe de poste en poste sans revenir sur la table.
$title = ' PHP 8.5 Released ';
$slug = $title
|> trim(...)
|> (fn($s) => str_replace(' ', '-', $s))
|> (fn($s) => str_replace('.', '', $s))
|> strtolower(...);
var_dump($slug); // "php-85-released"
// équivalent imbriqué : strtolower(str_replace(...(trim($title))))Cas d'usage : Remplacer des appels imbriqués illisibles ou des variables intermédiaires par un pipeline de transformations.
Échappement des données au moment de l'affichage selon le contexte (HTML, attribut, URL, JS). Dernière ligne de défense contre le XSS.
Comme emballer un colis fragile avant l'envoi : on protège le contenu en fonction de la destination.
// Contexte HTML
echo htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
// Contexte URL
echo urlencode($data);
// Contexte JS
echo json_encode($data);Cas d'usage : A chaque affichage de données dynamiques, adapte au contexte de sortie.
Fonctions natives PHP pour hasher et vérifier des mots de passe de manière sécurisée. Utilise bcrypt par défaut avec salt automatique.
Comme une empreinte digitale : on peut vérifier que c'est la bonne personne sans stocker son doigt.
// Stockage
$hash = password_hash($password, PASSWORD_DEFAULT);
// Verification
if (password_verify($inputPassword, $hash)) {
echo 'Mot de passe correct';
}Cas d'usage : Pour tout système d'authentification qui stocke des mots de passe.
Framework de test PHP moderne construit sur PHPUnit, avec une syntaxe expressive inspirée de Jest. Offre arch testing, parallel testing et une DX supérieure.
Comme PHPUnit avec un lifting : même moteur puissant, mais un intérieur plus agréable et moderne.
test('cart total applies discount', function () {
$cart = new Cart();
$cart->add(new Product(price: 100));
$cart->applyDiscount(10);
expect($cart->total())->toBe(90);
});Cas d'usage : Pour les équipes qui veulent une syntaxe de test plus lisible et productive.
FastCGI Process Manager : l'implémentation FastCGI principale de PHP pour les sites chargés. Il gère des pools de processus (uid, chroot, port distincts), trois modes d'engendrement (static, dynamic, ondemand), un slowlog des scripts lents et fastcgi_finish_request(). Nginx ou Apache lui transmettent les requêtes via socket.
Le chef de salle qui décide combien de serveurs travaillent selon l'affluence.
# /etc/php/8.4/fpm/pool.d/www.conf
[www]
listen = /run/php/php8.4-fpm.sock
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
request_slowlog_timeout = 5s
# nginx
# location ~ \.php$ { fastcgi_pass unix:/run/php/php8.4-fpm.sock; include fastcgi.conf; }Cas d'usage : Toute prod PHP derrière nginx : dimensionner pm.max_children selon la RAM, isoler les sites par pool, diagnostiquer les lenteurs via le slowlog.
Analyseur statique qui détecte les bugs sans exécuter le code. Il vérifie les types, les appels de méthodes, les propriétés inexistantes et plus selon le niveau configuré, de 0 à 10. Le niveau 10, ajouté dans PHPStan 2.0, signale même le mixed implicite.
Comme un correcteur orthographique pour le code : il repère les erreurs avant la publication.
# phpstan.neon
parameters:
level: 8
paths:
- src
# Commande
# vendor/bin/phpstan analyseCas d'usage : En CI/CD pour détecter les bugs de type et les erreurs logiques avant le déploiement.
Framework de tests unitaires standard en PHP. Fournit assertions, mocks, data providers, couverture de code et intégration CI.
Comme un laboratoire de contrôle qualité qui vérifie chaque pièce avant l'assemblage final.
class CartTest extends TestCase {
public function test_total_with_discount(): void {
$cart = new Cart();
$cart->add(new Product(price: 100));
$cart->applyDiscount(10);
$this->assertEquals(90, $cart->total());
}
}Cas d'usage : Pour tester toute logique métier et garantir la non-régression a chaque changement.
Capacité d'objets de types différents a répondre au même message (méthode). Permet de traiter des objets différents de manière uniforme via une interface commune.
Comme la touche Play : que ce soit Spotify, YouTube ou un CD, le résultat est de la musique.
interface Notifier {
public function send(string $msg): void;
}
class EmailNotifier implements Notifier { /* ... */ }
class SmsNotifier implements Notifier { /* ... */ }
function notify(Notifier $n, string $msg): void {
$n->send($msg); // fonctionne pour tout Notifier
}Cas d'usage : Pour écrire du code générique qui fonctionne avec n'importe quelle implémentation d'une interface.
Requêtes SQL paramétrées ou les valeurs sont envoyées séparément du code SQL. Protection native contre les injections SQL.
Comme un formulaire pre-imprime avec des cases vides : la structure est fixe, seules les données changent.
$stmt = $pdo->prepare(
'INSERT INTO users (name, email) VALUES (:name, :email)'
);
$stmt->execute([
'name' => $name,
'email' => $email,
]);Cas d'usage : Pour CHAQUE requête SQL qui inclut des données variables, sans exception.
Blocs get et set attachés directement à une propriété, introduits en PHP 8.4 (21 novembre 2024, RFC adoptée 42 voix contre 2). Ils remplacent les paires getter/setter et permettent des propriétés virtuelles, calculées sans stockage. Une propriété readonly ne peut pas avoir de hooks.
Un compteur électrique qui affiche la consommation calculée quand on le regarde, sans stocker le chiffre nulle part.
class Locale
{
public string $countryCode {
// validation à l'écriture
set (string $v) { $this->countryCode = strtoupper($v); }
}
// propriété virtuelle : aucun stockage
public string $combined {
get => "{$this->lang}_{$this->countryCode}";
}
public function __construct(public string $lang) {}
}Cas d'usage : Valider ou normaliser une valeur à l'affectation, ou exposer une valeur dérivée comme une simple propriété, lisible par l'IDE et PHPStan.
PHP Standards Recommendations : normes communautaires du PHP-FIG définissant autoloading (PSR-4), coding style (PSR-12), logging (PSR-3), HTTP (PSR-7/15), container (PSR-11).
Comme le code de la route : des règles communes pour que tous les développeurs circulent dans le même sens.
// PSR-4 : App\Models\User -> src/Models/User.php
// PSR-12 : coding style
// PSR-3 : LoggerInterface
// PSR-7 : RequestInterface / ResponseInterface
// PSR-11 : ContainerInterfaceCas d'usage : Pour l'interopérabilité entre frameworks et libraries, et un code lisible par tous.
Standard PHP-FIG qui définit les interfaces des messages HTTP : RequestInterface, ServerRequestInterface, ResponseInterface, StreamInterface, UriInterface, UploadedFileInterface. Les messages sont immuables : chaque with*() retourne une nouvelle instance. Base des middlewares PSR-15 et des clients PSR-18.
Un formulaire administratif normalisé : chaque guichet le lit sans demander de version spéciale.
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
function handle(Request $request): Response
{
$name = $request->getQueryParams()['name'] ?? 'monde';
// immuable : withHeader() retourne une copie
$response = (new Response())
->withStatus(200)
->withHeader('Content-Type', 'text/plain');
$response->getBody()->write("Bonjour $name");
return $response;
}Cas d'usage : Écrire un middleware ou une bibliothèque compatible avec Slim, Laminas, Symfony (via bridge) sans dépendre d'un framework.
Propriétés PHP 8.1 initialisables une seule fois, puis immuables. PHP 8.2 étend cela aux classes entières (readonly class). PHP 8.3 autorise leur réinitialisation dans __clone(), PHP 8.4 fait de readonly l'équivalent de protected(set), et PHP 8.5 permet clone($obj, ['prop' => $v]) pour dériver un objet immuable.
Comme un tatouage : une fois fait, on ne peut plus le modifier.
readonly class UserDTO {
public function __construct(
public string $name,
public string $email,
) {}
// PHP 8.5 : « clone with » sur un objet readonly
public function withEmail(string $email): self {
return clone($this, ['email' => $email]);
}
}Cas d'usage : Pour les DTOs et Value Objects ou l'immutabilite garantit l'intégrité des données.
Outil de refactoring automatique qui modernise le code PHP en appliquant des règles de transformation. Peut migrer entre versions PHP et frameworks.
Comme un traducteur automatique qui met a jour un vieux livre dans un langage moderne.
// rector.php
return RectorConfig::configure()
->withPhpSets(php83: true)
->withPreparedSets(
deadCode: true,
codeQuality: true,
);Cas d'usage : Pour migrer un projet vers PHP 8.x ou moderniser du code legacy automatiquement.
Couche d'abstraction entre la logique métier et l'accès aux données. Le repository expose des méthodes métier et masque les détails de persistence.
Comme un bibliothécaire : tu lui demandes un livre par titre, il sait ou le trouver dans les rayons.
interface UserRepository {
public function findByEmail(string $email): ?User;
public function save(User $user): void;
}
class DoctrineUserRepository implements UserRepository {
// Implementation avec Doctrine ORM
}Cas d'usage : Pour découpler la logique métier de la base de données et faciliter les tests unitaires.
Registre central qui gère la création et la résolution des dépendances. C'est le coeur des frameworks modernes (Laravel, Symfony) pour l'injection de dépendances.
Comme un annuaire d'entreprise : quand tu as besoin d'un service, tu demandes au standard qui te met en relation.
// Enregistrement
$container->bind(Logger::class, FileLogger::class);
// Resolution automatique
$service = $container->make(OrderService::class);
// Les dependances sont resolues automatiquementCas d'usage : Dans tout framework PHP moderne pour gérer les dépendances et leur cycle de vie.
Attaque ou l'attaquant fixe l'ID de session d'un utilisateur avant qu'il se connecte, puis utilise cet ID pour usurper sa session.
Comme donner une clé de chambre d'hôtel a quelqu'un et attendre qu'il s'y installe pour entrer après lui.
// Apres login reussi, TOUJOURS regenerer
session_regenerate_id(true);
// Configuration stricte
ini_set('session.use_strict_mode', 1);
ini_set('session.use_only_cookies', 1);Cas d'usage : Après chaque changement de niveau de privilège (login, élévation de droits).
Une classe ne doit avoir qu'une seule raison de changer. Chaque classe se concentre sur une seule responsabilité métier.
Comme un employé spécialisé : le cuisinier cuisine, le serveur sert, le caissier encaisse.
// Mauvais: une classe qui fait tout
// class User { save(), sendEmail(), generatePDF() }
// Bon: responsabilites separees
class UserRepository { public function save(User $u) {} }
class UserMailer { public function welcome(User $u) {} }
class UserExporter { public function toPDF(User $u) {} }Cas d'usage : Toujours : chaque classe créée doit avoir une responsabilité claire et unique.
Pattern qui garantit qu'une classe n'a qu'une seule instance et fournit un point d'accès global. Souvent considère comme un anti-pattern en PHP moderne.
Comme le président d'un pays : il n'y en a qu'un seul a la fois, accessible par tous.
class Database {
private static ?self $instance = null;
private function __construct() {}
public static function getInstance(): self {
return self::$instance ??= new self();
}
}Cas d'usage : Rarement justifie en PHP moderne : le service container gère déjà les instances uniques.
Vulnérabilité ou un attaquant injecte du code SQL malveillant via des entrées utilisateur non assainies. L'une des failles les plus critiques et fréquentes.
Comme un intrus qui ajoute des instructions sur un bon de commande pour se faire livrer gratuitement.
// DANGEREUX
$sql = "SELECT * FROM users WHERE id = $id";
// SECURISE
$stmt = $pdo->prepare('SELECT * FROM users WHERE id = :id');
$stmt->execute(['id' => $id]);Cas d'usage : Prévention obligatoire sur TOUTE requête SQL utilisant des données externes.
Pattern qui définit une famille d'algorithmes interchangeables. Le client choisit la stratégie a utiliser a l'exécution sans modifier le code consommateur.
Comme choisir son moyen de transport : bus, vélo ou taxi, la destination reste la même.
interface ShippingStrategy {
public function calculate(Order $order): float;
}
class ExpressShipping implements ShippingStrategy { }
class StandardShipping implements ShippingStrategy { }
$order->setShipping(new ExpressShipping());Cas d'usage : Quand un comportement peut varier selon le contexte : calcul de prix, tri, notification.
Mécanisme de réutilisation de code dans les langages a héritage simple. Un trait permet d'injecter des méthodes dans plusieurs classes sans héritage.
Comme un kit d'accessoires qu'on peut ajouter a n'importe quelle voiture, peu importe la marque.
trait Timestampable {
public function getCreatedAt(): DateTime {
return $this->createdAt;
}
}
class Article {
use Timestampable;
}Cas d'usage : Pour partager du comportement commun (logging, timestamps, soft delete) entre classes non liées par héritage.
Union (A|B) accepte l'un OU l'autre type (PHP 8.0). Intersection (A&B) exige que la valeur implémente TOUS les types (PHP 8.1). PHP 8.2 permet de les combiner en forme normale disjonctive : (A&B)|null, l'intersection devant être entre parenthèses.
Union : un billet accepte en euros OU en dollars. Intersection : un candidat qui parle français ET anglais.
// Union (PHP 8.0)
function parse(string|int $input): string { }
// Intersection (PHP 8.1)
function save(Countable&Iterator $items): void { }
// DNF : intersection OU null (PHP 8.2)
function find((Countable&Iterator)|null $items): void { }Cas d'usage : Pour exprimer des contraintes de type précises et réduire les erreurs a l'exécution.
Syntaxe PHP 8.4 qui sépare la visibilité en lecture et en écriture d'une propriété : public private(set) se lit partout mais ne s'écrit que dans la classe. La visibilité d'écriture doit être au moins aussi restrictive que celle de lecture, et la propriété doit être typée. readonly équivaut désormais à protected(set).
Une vitrine de magasin : tout le monde voit les articles, seul le personnel peut les déplacer.
class PhpVersion
{
public private(set) string $version = '8.4';
public function increment(): void
{
[$major, $minor] = explode('.', $this->version);
$this->version = $major . '.' . ($minor + 1);
}
}
$v = new PhpVersion();
echo $v->version; // OK
$v->version = '9'; // Error : écriture privéeCas d'usage : Exposer l'état d'un objet en lecture sans getter, tout en gardant le contrôle des mutations dans la classe.
Extension PHP de debugging et profilage. Permet le step debugging, le stack trace détaillé, la couverture de code et le profilage de performance.
Comme une caméra au ralenti qui permet de voir chaque étape de l'exécution en détail.
; php.ini
zend_extension=xdebug
xdebug.mode=debug
xdebug.start_with_request=yes
xdebug.client_host=127.0.0.1
xdebug.client_port=9003Cas d'usage : En développement pour debugger pas-a-pas, analyser les performances et générer la couverture de code.
Vulnérabilité permettant l'injection de scripts malveillants dans une page web vue par d'autres utilisateurs. Vole des sessions, redirigé, défiguré.
Comme quelqu'un qui colle un faux panneau dans un magasin pour tromper les clients.
// DANGEREUX
echo "Bonjour $username";
// SECURISE
echo 'Bonjour ' . htmlspecialchars($username, ENT_QUOTES, 'UTF-8');Cas d'usage : A chaque affichage de données dynamiques dans du HTML, sans exception.