Module 1 / 8 · 90 min
01. Installation et analyse reproductibles
Faire analyser le même contrat au poste et en CI.
Comprendre le mécanisme
PHPStan examine le code et ses types sans exécuter les parcours métier habituels. Son résultat dépend de sa version, de la configuration, des extensions, des chemins et de la cible PHP. Une installation locale de développement avec lock versionné rend le contrôle plus reproductible qu’un outil global mis à jour sans suivi. Distinguez le PHP qui exécute l’analyse et la version cible décrite par la configuration.
Raisonner et vérifier
Analysez les classes utiles et leurs contrats, avec les stubs ou extensions nécessaires. Une découverte de symboles mal configurée peut produire des erreurs trompeuses ; exclure massivement le code masque le problème. La pipeline doit échouer si l’analyse échoue et rendre les diagnostics exploitables. Ne publiez pas les secrets du fichier d’environnement pour obtenir un rapport de types.
Version de l’analyseur
La version de PHPStan influence les diagnostics. Les versions peuvent faire évoluer les vérifications. Deux versions peuvent comprendre différemment une annotation ou ajouter un diagnostic. Enregistrez la version utilisée avec le rapport pour pouvoir reproduire le résultat lors d’une revue de release.
Erreur fréquente à comprendre Tout exécutable PHPStan produit le même rapport pour toujours.
Les versions peuvent faire évoluer les vérifications.
Dépendances verrouillées
Le lock aide à reproduire les dépendances. Il décrit les dépendances résolues, pas les credentials. Exécutez composer install à partir du lock révisé plutôt que résoudre de nouvelles versions à chaque job. Les extensions et leurs dépendances influencent aussi le résultat, pas seulement le binaire principal.
Erreur fréquente à comprendre Le lock contient les secrets nécessaires à l’analyse.
Il décrit les dépendances résolues, pas les credentials.
Version cible et runtime
La cible PHP doit être configurée correctement. L’analyse et le runtime sont des environnements distincts. phpVersion: 80400 décrit PHP 8.4 pour l’analyse. Cette configuration n’installe aucun interpréteur ; vérifiez séparément les versions de PHP en CLI, dans les workers et dans le serveur web.
Erreur fréquente à comprendre phpVersion met automatiquement à jour l’interpréteur réel.
L’analyse et le runtime sont des environnements distincts.
Périmètre des chemins
Les chemins analysés déterminent la couverture. Un fichier exclu échappe aux contrôles concernés. Si seul src est analysé, un script d’import placé dans bin peut rester hors rapport. Inventoriez les points d’entrée et justifiez exclusions et code généré avant d’interpréter une suite verte.
Erreur fréquente à comprendre Exclure src conserve une analyse complète de src.
Un fichier exclu échappe aux contrôles concernés.
Extensions de framework
Les extensions peuvent préciser des contrats de framework. La découverte de symboles doit correspondre aux bibliothèques. Une extension Symfony ou Doctrine décrit des comportements que le code dynamique rend difficiles à inférer. Vérifiez sa compatibilité et gardez un test d’exécution pour les services ou repositories réellement utilisés.
Erreur fréquente à comprendre Un framework dynamique n’a jamais besoin de configuration adaptée.
La découverte de symboles doit correspondre aux bibliothèques.
Échec observable
Une erreur d’analyse doit faire échouer la CI prévue. Le contrôle doit participer à la décision de qualité. Le pipeline doit respecter le code de sortie de l’analyseur. Une commande suivie de true peut imprimer des erreurs tout en laissant publier ; testez le job avec un défaut volontaire dans une branche de laboratoire.
Erreur fréquente à comprendre La CI doit ignorer tout code de retour non nul.
Le contrôle doit participer à la décision de qualité.
Même configuration
Les configurations locale et CI doivent être cohérentes. La version et les options peuvent diverger. Un fichier local prioritaire peut masquer la configuration distribuée utilisée en CI. Appelez explicitement le fichier attendu et comparez niveau, chemins et extensions avant de conclure à une différence de comportement inexplicable.
Erreur fréquente à comprendre Une installation globale non suivie est toujours identique à la CI.
La version et les options peuvent diverger.
Analyse sans parcours
L’analyse statique ne rejoue pas tous les parcours métier. Son périmètre diffère d’une exécution fonctionnelle. PHPStan raisonne sur le code et ses contrats ; il ne simule pas chaque demande utilisateur. Les permissions, courses concurrentes et effets prestataire doivent disposer d’autres preuves ciblées.
Erreur fréquente à comprendre PHPStan se connecte automatiquement à tous les scénarios réels.
Son périmètre diffère d’une exécution fonctionnelle.
Sans secrets de production
Les secrets ne sont pas nécessaires à un rapport de types. Les diagnostics peuvent rester sans credentials réels. Ne chargez pas une connexion réelle simplement pour découvrir des types. Utilisez des contrats et une configuration de bootstrap minimale ; un analyseur ne doit pas devenir une voie d’accès aux données clientes.
Erreur fréquente à comprendre Il faut publier .env pour comprendre un type de retour.
Les diagnostics peuvent rester sans credentials réels.
Découverte des symboles
Une mauvaise découverte doit être corrigée à sa cause. L’exclusion masque la couverture au lieu de rétablir les symboles. Si une classe reste inconnue, contrôlez autoload, namespace et dépendances. Un ignore global ferait disparaître le symptôme tout en laissant l’analyse perdre des informations sur les appels concernés.
Erreur fréquente à comprendre Exclure tout le code est une correction de contrat.
L’exclusion masque la couverture au lieu de rétablir les symboles.
Atelier guidé : lire, expliquer et vérifier le code
parameters:
level: 8
phpVersion: 80400
paths:
- src
Lisez chaque clé de la configuration puis comparez-la aux commandes réellement exécutées en CI. La version cible n’est ni un gestionnaire de runtime ni une garantie de compatibilité de toutes les dépendances. Produisez un rapport reproductible à partir du même lock et du même fichier de configuration.
La valeur décrit la version cible, sans provisionner le runtime. Le paramètre n’installe aucun interpréteur. Seul src est explicitement dans les chemins montrés. Le typage ne remplace pas les scénarios exécutés.
Travail pratique : Exécutez l’analyse localement et en CI sur le même commit avec le même lock, puis introduisez un type de retour incohérent.
Critères de correction : Les deux environnements doivent signaler la régression et la CI doit retourner un échec. Conservez la version et le chemin de configuration dans le diagnostic, sans contenu sensible.
Exemple commenté
composer require --dev phpstan/phpstan
vendor/bin/phpstan analyse -c phpstan.neon --no-progress
# Exemple de configuration pour le laboratoire
parameters:
level: 8
paths:
- src
phpVersion: 80400
La configuration vise PHP 8.4 ; le niveau choisi est un point de départ pédagogique, pas une certification.
Exercice de mise en pratique
Exécutez l’analyse localement et en CI sur le même commit avec le même lock, puis introduisez un type de retour incohérent.
Voir une proposition de correction
Les deux environnements doivent signaler la régression et la CI doit retourner un échec. Conservez la version et le chemin de configuration dans le diagnostic, sans contenu sensible.
- Outil versionné.
- Cible PHP définie.
- Échec propagé à la CI.
Contrôle de connaissances
Un rapport PHPStan dépend-il seulement du contenu de src ?
Réponse expliquée : Non, version, configuration et extensions comptent aussi — L’environnement d’analyse fait partie du contrat.
Cours associé : 01. Installation et analyse reproductibles ↗
Documentation de référence ↗ https://phpstan.org/user-guide/getting-started
Module 2 / 8 · 90 min
02. Niveaux 0 à 10 et maîtrise de mixed
Choisir une progression mesurable au lieu d’un score symbolique.
Comprendre le mécanisme
Les niveaux PHPStan sont cumulatifs : un niveau supérieur ajoute des vérifications à ceux qui le précèdent. Au référentiel vérifié pour ce cours, ils vont de 0 à 10 ; le niveau 9 restreint fortement le mixed explicite et le niveau 10 étend la sévérité au mixed implicite. L’alias max suit le plus haut niveau lors des évolutions de l’outil, ce qui demande une politique d’upgrade.
Raisonner et vérifier
mixed représente une information absente ou très générale ; un cast ou un PHPDoc inventé ne constitue pas une validation d’entrée. Réduisez l’incertitude par des gardes et des contrats précis aux frontières. Montez le niveau par étapes suivies, avec critères d’acceptation et budget de correction. Un niveau élevé ne démontre ni absence d’injection ni autorisation correcte : ces propriétés dépassent le typage seul.
Niveaux cumulatifs
Les niveaux sont cumulatifs. La sévérité s’ajoute au socle antérieur. Monter de niveau conserve les contrôles précédents. Gardez une fixture de diagnostic déjà détecté au niveau inférieur pour vérifier que votre changement de configuration n’a pas accidentellement retiré des règles utiles.
Erreur fréquente à comprendre Le niveau supérieur désactive tous les précédents.
La sévérité s’ajoute au socle antérieur.
Échelle 0 à 10
PHPStan 2.x propose des niveaux de 0 à 10. Le référentiel du cours inclut les niveaux 9 et 10. Dans PHPStan 2.x, zéro est le point d’entrée le plus permissif et dix le plus strict de cette échelle. La version doit accompagner cette indication afin d’éviter une promesse valable pour toute version future.
Erreur fréquente à comprendre Le plus haut niveau documenté du cours est 8.
Le référentiel du cours inclut les niveaux 9 et 10.
Valeur max
max suit le plus haut niveau disponible. Une mise à jour peut ajouter des contrôles au plus haut niveau. Le mot max suit le sommet disponible après mise à jour. Une release de l’outil peut donc ajouter du travail ; examinez les diagnostics dans une mise à jour dédiée et explicable.
Erreur fréquente à comprendre max fige éternellement le niveau choisi aujourd’hui.
Une mise à jour peut ajouter des contrôles au plus haut niveau.
Mixed explicite
Le niveau 9 restreint mixed explicite. L’objectif est de limiter les opérations sans type précis. Au niveau neuf, appeler name sur un mixed n’est pas justifié. Vérifiez une interface ou validez une structure puis accédez à son contrat, au lieu d’ajouter une annotation locale qui prétend savoir.
Erreur fréquente à comprendre Le niveau 9 rend tout mixed librement utilisable.
L’objectif est de limiter les opérations sans type précis.
Mixed implicite
Le niveau 10 étend le contrôle au mixed implicite. Il augmente la sévérité sur les informations absentes. Le niveau dix ajoute des contrôles sur les valeurs restées mixed faute de déclaration. Corrigez les frontières et signatures, plutôt que rendre toutes les valeurs explicitement mixed pour changer seulement le diagnostic.
Erreur fréquente à comprendre Le niveau 10 supprime les diagnostics de types manquants.
Il augmente la sévérité sur les informations absentes.
Réduction réelle
Une garde réelle peut réduire un type. La conversion ne vérifie pas nécessairement le contrat d’entrée. Après un instanceof sur une interface, ses méthodes deviennent disponibles dans la branche admise. Le chemin contraire doit retourner ou lever une exception avant tout appel qui exige ce contrat.
Erreur fréquente à comprendre Un cast arbitraire prouve toute validation de donnée.
La conversion ne vérifie pas nécessairement le contrat d’entrée.
Type et permission
Un niveau élevé ne prouve pas les permissions métier. Le typage ne connaît pas automatiquement chaque règle d’accès. Un objet Reservation correctement typé peut appartenir à un autre client. Ajoutez une décision de périmètre sur acteur, tenant et ressource ; le niveau maximal ne fournit pas cette relation métier.
Erreur fréquente à comprendre Le niveau max certifie toute autorisation d’objet.
Le typage ne connaît pas automatiquement chaque règle d’accès.
Progression planifiée
La montée de niveau doit avoir un plan de correction. La progression doit changer les contrats et comportements concernés. Choisissez un niveau cible, des propriétaires et un ordre de correction. Traitez d’abord les frontières très utilisées ; chaque étape doit garder les diagnostics nouveaux visibles et les tests fonctionnels exécutables.
Erreur fréquente à comprendre Augmenter le nombre sans traiter les écarts suffit au code.
La progression doit changer les contrats et comportements concernés.
Dette visible
Une baseline peut décrire de la dette. Elle reporte des diagnostics sans modifier le code. Une baseline permet de distinguer une dette connue du nouveau code. Elle doit rester revue et bornée ; régénérer automatiquement toutes les erreurs à chaque analyse détruirait cette distinction.
Erreur fréquente à comprendre Une baseline transforme les défauts en comportements corrects.
Elle reporte des diagnostics sans modifier le code.
Vérification runtime
Les tests d’exécution complètent l’analyse. Les techniques ont des périmètres complémentaires. Une annotation précise peut mentir sur un résultat externe. Un test de parsing avec null, structure incomplète et mauvais type vérifie que le chemin d’exécution établit effectivement ce que l’analyse suppose.
Erreur fréquente à comprendre Une analyse verte empêche toute erreur runtime imaginable.
Les techniques ont des périmètres complémentaires.
Atelier guidé : lire, expliquer et vérifier le code
<?php
declare(strict_types=1);
function label(mixed $value): string {
return $value->name();
}
Le paramètre de l’extrait est explicitement mixed et le corps appelle une méthode sans vérifier son existence. Introduisez une interface si le contrat est connu, ou une garde réelle lorsque la frontière reste ouverte. Exécutez aussi le refus avec une valeur incompatible pour vérifier le comportement du programme.
La suppression masque l’incertitude. Une annotation mensongère ne valide pas l’entrée. mixed n’accorde pas toutes les capacités. L’opération doit être justifiée par un type réellement établi.
Travail pratique : Analysez une donnée JSON inconnue à différents niveaux puis remplacez un accès direct par une garde de structure.
Critères de correction : Comparez les diagnostics et vérifiez les refus à l’exécution avec null, tableau et chaîne. Documentez niveau retenu et raisons des écarts temporaires.
Exemple commenté
Entrée mixed → garde exécutée → type réduit → opération autorisée par ce type
Le passage de type doit correspondre à une observation réelle, pas à un commentaire rassurant.
Exercice de mise en pratique
Analysez une donnée JSON inconnue à différents niveaux puis remplacez un accès direct par une garde de structure.
Voir une proposition de correction
Comparez les diagnostics et vérifiez les refus à l’exécution avec null, tableau et chaîne. Documentez niveau retenu et raisons des écarts temporaires.
- Niveaux cumulatifs.
- Mixed réduit réellement.
- Max suivi lors des upgrades.
Contrôle de connaissances
Les niveaux supérieurs désactivent-ils les règles des niveaux inférieurs ?
Réponse expliquée : Non, les niveaux sont cumulatifs — Ils ajoutent des contrôles au socle précédent.
Cours associé : 02. Niveaux 0 à 10 et maîtrise de mixed ↗
Documentation de référence ↗ https://phpstan.org/user-guide/rule-levels
Module 3 / 8 · 90 min
03. Types riches et validation des frontières
Utiliser les formes de données sans prétendre valider le réseau par PHPDoc.
Comprendre le mécanisme
Les PHPDocs peuvent exprimer unions, listes, tableaux de forme précise et contraintes utiles à l’analyse. Ces annotations décrivent un contrat ; elles ne transforment pas un corps HTTP en donnée valide. Écrire qu’un tableau contient amount positif ne rend pas vraie une entrée négative. Le code exécuté doit refuser les types, clés et valeurs non conformes avant de produire l’objet du domaine.
Raisonner et vérifier
Séparez parseur, validateur et modèle métier. Une garde valide d’abord la structure puis les invariants : entier n’implique pas montant autorisé, chaîne n’implique pas destination sûre. Préférez des DTO et objets de valeur pour éviter de disperser des tableaux aux clés approximatives. Les erreurs d’entrée doivent être testées sans convertir silencieusement toute valeur en type attendu.
Décrire puis établir
Un PHPDoc décrit un contrat. Une annotation n’exécute pas une garde d’entrée. Le commentaire array{amount: positive-int} n’exécute aucune vérification du JSON. Le code doit contrôler structure, type natif et bornes avant de transmettre la valeur à une fonction qui suppose ce contrat.
Erreur fréquente à comprendre Un PHPDoc valide automatiquement le JSON réseau.
Une annotation n’exécute pas une garde d’entrée.
Formes de tableau
Une forme de tableau précise ses clés attendues. Les données externes doivent établir ce contrat. Une array shape nomme les clés obligatoires et optionnelles. Testez clé manquante, clé présente avec null et valeur de mauvais type : ces situations ont des contrats distincts qu’un simple accès au tableau masque.
Erreur fréquente à comprendre Toute array shape garantit la présence réelle de ses clés sans contrôle.
Les données externes doivent établir ce contrat.
Unions
Une union indique plusieurs types possibles. Une opération doit être compatible avec les possibilités restantes. Un retour User|null demande de gérer l’absence avant d’appeler une méthode utilisateur. Les unions documentent plusieurs chemins ; elles ne signifient pas que l’appelant peut choisir arbitrairement celui qui l’arrange.
Erreur fréquente à comprendre Une union autorise toute méthode de l’un de ses membres.
Une opération doit être compatible avec les possibilités restantes.
Type et domaine
Une garde peut vérifier type et valeur. La positivité est un invariant supplémentaire. is_int puis une comparaison positive rejettent la chaîne '12'. Ajoutez un plafond et une règle de devise pour un montant ; les types raffinés ne doivent pas dépasser ce que la garde établit.
Erreur fréquente à comprendre is_int garantit que tout montant est positif.
La positivité est un invariant supplémentaire.
Conversions destructrices
Un cast peut masquer une entrée incorrecte. La conversion ne remplace pas une politique d’acceptation. Caster 'inconnu' en entier peut produire zéro et perdre l’erreur initiale. Définissez les représentations admises puis convertissez après validation, en vérifiant dépassement et conservation de la précision.
Erreur fréquente à comprendre Caster toute entrée en int vérifie la grammaire métier.
La conversion ne remplace pas une politique d’acceptation.
DTO validé
Un DTO peut structurer des données validées. La permission demeure une décision distincte. Construisez un objet d’entrée seulement après validation, ou faites refuser son constructeur en cas d’invariant violé. Un nom comme ValidPayment ne rend pas sûr un constructeur qui accepte toute donnée sans contrôle.
Erreur fréquente à comprendre Construire un DTO prouve automatiquement l’autorisation.
La permission demeure une décision distincte.
Plafond métier
Un entier positif peut dépasser un plafond métier. Les limites du domaine peuvent être plus étroites. Un positive-int de plusieurs milliards peut être incompatible avec un remboursement de dix euros. Vérifiez solde, autorisation et limites en contexte ; la propriété arithmétique positive reste une seule condition parmi plusieurs.
Erreur fréquente à comprendre positive-int suffit à autoriser tout montant.
Les limites du domaine peuvent être plus étroites.
Matrice de refus
Les erreurs de frontière doivent être testées. Les absences et mauvais types doivent être refusés selon le contrat. Envoyez tableaux, flottants, chaînes numériques, négatifs et valeurs extrêmes. Vérifiez l’erreur publique et l’absence d’écriture, pas seulement que PHPStan continue d’inférer int à la sortie nominale.
Erreur fréquente à comprendre Seul un exemple nominal prouve toute validation.
Les absences et mauvais types doivent être refusés selon le contrat.
Parsing distinct
Le parsing et la validation sont des étapes différentes. Structure et invariants peuvent encore être invalides. json_decode peut produire un tableau valide syntaxiquement qui ne contient pas les champs requis. Une exception de parsing et une violation de schéma doivent être traitées comme deux causes différentes.
Erreur fréquente à comprendre Un JSON syntaxiquement correct est toujours conforme au domaine.
Structure et invariants peuvent encore être invalides.
Politique de conversion
Un contrat doit définir les conversions acceptées. L’API choisit explicitement sa grammaire d’entrée. Une API peut accepter une chaîne décimale par contrat explicite ; une autre exige un entier JSON. Documentez ce choix et évitez qu’un cast opportuniste élargisse silencieusement les entrées acceptées.
Erreur fréquente à comprendre La chaîne numérique doit toujours être acceptée comme entier dans toute API.
L’API choisit explicitement sa grammaire d’entrée.
Atelier guidé : lire, expliquer et vérifier le code
<?php
declare(strict_types=1);
function accept(mixed $value): bool {
return is_int($value) && $value > 0;
}
echo accept('12') ? 'accepted' : 'rejected';
Évaluez is_int avant la comparaison numérique : la valeur fournie est une chaîne et échoue donc à la première condition. Comparez ensuite avec un entier positif, zéro et un tableau. Pour transformer cet exemple en frontière de paiement, ajoutez un plafond métier et les contrôles d’autorisation nécessaires.
Le résultat affiché est un libellé. La fonction est syntaxiquement valide. La garde demande un int ; la valeur reçue est une string. Le contrat ne prévoit pas ici de conversion de chaîne.
Travail pratique : Envoyez 12, "12", 0, -1 et null à la frontière de laboratoire. Comparez un cast aveugle avec la garde.
Critères de correction : Seul l’entier positif respecte ce contrat strict. Vérifiez ensuite la limite métier et la permission séparément. Une API acceptant aussi une chaîne doit définir explicitement sa grammaire de conversion.
Exemple commenté
<?php
declare(strict_types=1);
function positiveAmount(mixed $value): int
{
if (!is_int($value) || $value <= 0) {
throw new InvalidArgumentException('Montant invalide');
}
return $value;
}
La garde vérifie type et valeur ; elle ne décide pas si un utilisateur peut payer ce montant.
Exercice de mise en pratique
Envoyez 12, "12", 0, -1 et null à la frontière de laboratoire. Comparez un cast aveugle avec la garde.
Voir une proposition de correction
Seul l’entier positif respecte ce contrat strict. Vérifiez ensuite la limite métier et la permission séparément. Une API acceptant aussi une chaîne doit définir explicitement sa grammaire de conversion.
- Annotations honnêtes.
- Gardes exécutées.
- Invariants distincts des types.
Contrôle de connaissances
Un PHPDoc array{amount: positive-int} valide-t-il un JSON reçu ?
Réponse expliquée : Non, il décrit un contrat à établir par le code — Les annotations ne sont pas un validateur de réseau.
Cours associé : 03. Types riches et validation des frontières ↗
Documentation de référence ↗ https://phpstan.org/writing-php-code/phpdoc-types
Module 4 / 8 · 90 min
04. Génériques, collections et contrats
Préserver le type des éléments à travers les abstractions.
Comprendre le mécanisme
Les génériques exprimés en PHPDoc permettent de relier types d’entrée, de sortie et de collections. Une collection de Reservation peut ainsi garder son type au fil d’un repository sans retomber dans des tableaux non spécifiés. Cette information améliore la détection d’appels incohérents, mais ne prouve pas que les réservations appartiennent à l’utilisateur courant. Un paramètre de type n’exprime pas tout le contexte d’accès.
Raisonner et vérifier
N’élargissez pas un contrat uniquement pour faire disparaître un diagnostic. Vérifiez la variance et les capacités réellement promises par l’abstraction. Pour les données externes, construisez les objets après validation ; pour les objets persistés, appliquez les filtres et décisions de droits nécessaires. Une extension ou un stub doit décrire le comportement réel de la bibliothèque ciblée.
Relier entrée et sortie
Un paramètre T relie des types dans un contrat. Le générique décrit une relation pour l’analyse. Un paramètre T permet de dire que firstOrNull conserve le type des éléments reçus. Sans ce lien, retourner simplement mixed ferait perdre à chaque appelant la connaissance déjà disponible sur sa collection.
Erreur fréquente à comprendre T chiffre la valeur de la collection.
Le générique décrit une relation pour l’analyse.
Listes indexées
list<T> décrit les éléments d’une liste. Le type ne donne pas une autorisation d’accès. list<T> décrit une suite à indices entiers contigus depuis zéro. Après une opération qui conserve des clés dispersées, réindexez seulement si cela correspond au contrat ; un tableau quelconque n’est pas nécessairement une liste.
Erreur fréquente à comprendre list<T> prouve la propriété métier des éléments.
Le type ne donne pas une autorisation d’accès.
Absence explicite
Une sortie T ou null doit traiter null. La nullabilité reste dans le contrat. La liste vide produit null dans firstOrNull. L’appelant doit choisir un défaut, retourner une absence ou lever une erreur adaptée avant de traiter le résultat comme une instance certaine.
Erreur fréquente à comprendre Le générique supprime automatiquement tous les cas vides.
La nullabilité reste dans le contrat.
Accès cohérents
Une collection typée réduit les accès incohérents. Les permissions ne dérivent pas du seul nom de classe. Une collection Reservation évite de supposer qu’un élément est un User. Ajoutez les méthodes nécessaires au contrat et laissez l’analyse repérer les appels incohérents sans recourir à des casts de confort.
Erreur fréquente à comprendre Le nom Reservation accorde tous les droits de lecture.
Les permissions ne dérivent pas du seul nom de classe.
Variance et mutation
La variance doit respecter les capacités promises. Les entrées et sorties imposent des contraintes différentes. Une collection lisible d’un sous-type et une collection modifiable n’ont pas les mêmes possibilités de substitution. Si un appelant peut insérer un autre sous-type, la promesse faite au détenteur initial peut être violée.
Erreur fréquente à comprendre Tout élargissement de type est compatible avec toute substitution.
Les entrées et sorties imposent des contraintes différentes.
Entrées externes
Les données externes doivent être validées avant construction du modèle. Le commentaire ne remplace pas le contrôle runtime. Une annotation list<Order> autour d’un JSON ne construit aucun Order. Parsez chaque élément et vérifiez sa structure avant de former une collection dont les méthodes supposent des objets valides.
Erreur fréquente à comprendre Une annotation générique transforme toute entrée hostile en objet sûr.
Le commentaire ne remplace pas le contrôle runtime.
Stubs honnêtes
Un stub doit décrire le comportement réel. Une description fausse peut tromper l’analyse. Un stub de bibliothèque doit conserver null et les types d’erreur réellement possibles. Enlever une possibilité pour rendre l’analyse verte ne change pas le comportement du fournisseur exécuté en production.
Erreur fréquente à comprendre Un stub peut inventer un retour pour faire taire toute erreur.
Une description fausse peut tromper l’analyse.
Périmètre du repository
Les repositories doivent conserver leurs règles de périmètre. Le filtre métier doit être implémenté. Un repository typé doit aussi filtrer le tenant ou appliquer la politique appropriée. La signature Order ne signifie pas Order autorisé pour cet acteur ; testez les identifiants d’un autre périmètre.
Erreur fréquente à comprendre Un retour list<Reservation> filtre automatiquement le tenant.
Le filtre métier doit être implémenté.
Cas vide
Les tests doivent couvrir une liste vide. La non-vacuité demande une contrainte différente. Vérifiez une collection vide avant le scénario à plusieurs éléments. Ce cas expose le contrat nullable et les opérations qui supposent sans preuve un premier élément toujours présent.
Erreur fréquente à comprendre Une liste typée est nécessairement non vide.
La non-vacuité demande une contrainte différente.
Abstraction précise
Une abstraction doit préciser les types d’éléments. Cela retire des informations utiles à l’analyse. Une interface de collection doit déclarer le type de ses valeurs et de ses clés lorsque ces deux informations comptent. Un simple iterable perd le lien qui rend les traitements suivants vérifiables.
Erreur fréquente à comprendre Remplacer tous les éléments par mixed améliore toujours la précision.
Cela retire des informations utiles à l’analyse.
Atelier guidé : lire, expliquer et vérifier le code
<?php
declare(strict_types=1);
/** @template T
* @param list<T> $items
* @return T|null
*/
function firstOrNull(array $items): mixed {
return $items[0] ?? null;
}
$result = firstOrNull([]);
Suivez le type T depuis le paramètre jusqu’au retour puis exécutez le cas de la liste vide. La présence de null dans la signature décrit un résultat réel. Proposez un traitement d’absence compatible avec le métier, sans remplacer la signature par une promesse artificiellement plus forte.
Le générique relie des types, pas les permissions. La sortie annonce l’absence et le code la produit ici. La fonction ne crée pas un élément. Le type list ne donne pas cette cardinalité minimale.
Travail pratique : Utilisez la fonction avec une liste d’objets puis une liste de chaînes. Analysez un appel de méthode sans garde du résultat.
Critères de correction : L’analyse doit conserver le type de chaque liste et signaler le cas nullable pertinent. Ajoutez une garde explicite ; vérifiez aussi les listes vides à l’exécution.
Exemple commenté
<?php
declare(strict_types=1);
/**
* @template T
* @param list<T> $items
* @return T|null
*/
function firstOrNull(array $items): mixed
{
return $items[0] ?? null;
}
La relation T est conservée par l’analyse, tandis que null reste une issue possible.
Exercice de mise en pratique
Utilisez la fonction avec une liste d’objets puis une liste de chaînes. Analysez un appel de méthode sans garde du résultat.
Voir une proposition de correction
L’analyse doit conserver le type de chaque liste et signaler le cas nullable pertinent. Ajoutez une garde explicite ; vérifiez aussi les listes vides à l’exécution.
- Relations de types conservées.
- Nullable traité.
- Droits hors du seul paramètre T.
Contrôle de connaissances
Que permet un paramètre générique T ?
Réponse expliquée : Relier les types dans un contrat réutilisable — Il exprime une relation de types.
Cours associé : 04. Génériques, collections et contrats ↗
Documentation de référence ↗ https://phpstan.org/blog/generics-in-php-using-phpdocs
Module 5 / 8 · 90 min
05. Réduction de types et assertions honnêtes
Faire correspondre preuve statique et garde réelle.
Comprendre le mécanisme
PHPStan réduit un type après certaines conditions et peut comprendre des fonctions de garde annotées avec phpstan-assert. Cette annotation est une promesse de comportement à vérifier dans le corps de la fonction. Une assertion documentaire qui ment peut conduire l’analyse à accepter un accès invalide. L’instruction assert de PHP ne doit pas porter seule une validation de sécurité indispensable, car sa configuration d’exécution peut la rendre inactive.
Raisonner et vérifier
Utilisez des conditions exécutées qui refusent le cas invalide. Testez la garde et ses chemins de retour, puis décrivez exactement ce qu’elle garantit. Elle peut établir une forme de donnée sans prouver son authenticité ou son autorisation. Évitez les PHPDocs locaux qui écrasent le type d’une donnée externe seulement pour faire passer la CI.
Garde exécutable
Une garde doit exécuter son refus. L’annotation décrit une promesse du code. Une fonction requireText doit tester réellement chaîne et non-vacuité, puis refuser le reste. Son annotation phpstan-assert décrit la propriété qui devient vraie après un retour normal de cette fonction.
Erreur fréquente à comprendre phpstan-assert génère le corps de validation.
L’annotation décrit une promesse du code.
Annotation trompeuse
Une annotation fausse peut tromper l’analyse. Le contrat doit être vérifié et testé. Un commentaire local peut affirmer qu’une valeur est un User alors que le réseau a fourni un entier. Préférez établir le type à la frontière et conserver une preuve visible dans le flot de contrôle.
Erreur fréquente à comprendre L’analyse corrige automatiquement toute promesse mensongère.
Le contrat doit être vérifié et testé.
Configuration assert
assert PHP dépend de sa configuration d’exécution. Une validation indispensable doit avoir un refus garanti. Les assertions PHP peuvent être désactivées selon la configuration de compilation et d’exécution. Une validation indispensable doit rester un contrôle explicite dont l’absence ne dépend pas d’une option d’optimisation.
Erreur fréquente à comprendre assert est toujours une garde de sécurité active en production.
Une validation indispensable doit avoir un refus garanti.
Branches d’une union
Une condition peut réduire une union. La preuve doit correspondre au chemin réellement pris. Dans une branche où value est une string, strlen devient cohérent. Vérifiez le chemin des autres types et la sortie de chaque branche ; une condition sans refus ne protège pas le code placé ensuite.
Erreur fréquente à comprendre Une condition non exécutée valide quand même l’entrée réseau.
La preuve doit correspondre au chemin réellement pris.
Chaîne non vide
non-empty-string n’est pas une preuve d’innocuité HTML. Le contexte de sortie exige d’autres contrôles. Un texte '<script>' est non vide. L’innocuité HTML, le paramétrage SQL et l’admission d’une destination URL nécessitent des protections propres à leur contexte, distinctes de la simple longueur.
Erreur fréquente à comprendre Toute chaîne non vide est sûre pour innerHTML.
Le contexte de sortie exige d’autres contrôles.
Tester le refus
Un refus de garde doit être testé. Les chemins invalides demandent une vérification réelle. Appelez la garde avec null, chaîne vide et type inattendu. Une exception attendue et l’absence d’effet aval démontrent que l’annotation décrit bien un contrôle exécuté, plutôt qu’une convention ignorée.
Erreur fréquente à comprendre Le seul PHPDoc suffit à prouver les exceptions.
Les chemins invalides demandent une vérification réelle.
Authenticité distincte
Un type précis ne prouve pas l’authenticité. Le type et la provenance sont deux propriétés. Une structure de jeton correctement typée peut être forgée. La signature, l’émetteur et le destinataire demandent leur validation ; un objet Claims n’établit pas à lui seul une relation de confiance.
Erreur fréquente à comprendre Une chaîne de type correct est nécessairement signée.
Le type et la provenance sont deux propriétés.
PHPDoc local
Les PHPDocs locaux doivent rester honnêtes. Il peut masquer l’incertitude au lieu de la résoudre. Réservez les annotations locales aux limites réellement connues et explicables de l’analyse. Si une validation manque dans le programme, ajoutez ce code au lieu de modifier uniquement l’information donnée à l’outil.
Erreur fréquente à comprendre Un @var inventé est une correction de toute donnée externe.
Il peut masquer l’incertitude au lieu de la résoudre.
Structure et droit
Une garde de structure ne donne pas de droit métier. Le modèle de permissions reste distinct. Une entrée contenant projectId:int peut viser le projet d’un tiers. Après validation structurelle, chargez la ressource dans le bon périmètre et appliquez la décision d’autorisation avant la mutation.
Erreur fréquente à comprendre Une array shape valide autorise toute opération.
Le modèle de permissions reste distinct.
Exception explicite
Une exception explicite peut imposer le rejet. Le comportement doit respecter la promesse de validation. Une InvalidArgumentException permet de couper le chemin invalide. L’analyse peut alors déduire le type sur le chemin restant ; testez aussi que le gestionnaire d’erreur public ne divulgue pas la valeur sensible refusée.
Erreur fréquente à comprendre Une garde peut retourner normalement sur toute entrée invalide.
Le comportement doit respecter la promesse de validation.
Atelier guidé : lire, expliquer et vérifier le code
<?php
declare(strict_types=1);
/** @phpstan-assert non-empty-string $value */
function requireText(mixed $value): void {
// aucune garde exécutée
}
requireText(null);
echo 'continued';
Dans l’extrait, le corps ne fait rien et null traverse la fonction. L’annotation ne produit donc aucun arrêt à l’exécution. Ajoutez une garde dont le retour normal garantit exactement non-empty-string, puis testez valeur vide, null et valeur admise sans dépendre d’assert PHP.
Le commentaire n’exécute pas le refus ; le programme continue. Aucun contrôle PHP natif n’est généré par ce PHPDoc. Aucune opération de validation ou transformation ne le fait. L’analyse ne réécrit pas la fonction.
Travail pratique : Retirez temporairement la condition dans le laboratoire, comparez l’analyse puis testez null et chaîne vide à l’exécution.
Critères de correction : La promesse peut tromper l’analyse si le corps ment. Restaurez la garde et ajoutez des tests des entrées invalides, puis vérifiez que les usages contextuels restent contrôlés.
Exemple commenté
<?php
declare(strict_types=1);
/** @phpstan-assert non-empty-string $value */
function requireNonEmpty(mixed $value): void
{
if (!is_string($value) || $value === '') {
throw new InvalidArgumentException('Chaîne requise');
}
}
Le refus réel justifie la promesse non-empty-string. Cela n’assainit pas cette chaîne pour tous les contextes.
Exercice de mise en pratique
Retirez temporairement la condition dans le laboratoire, comparez l’analyse puis testez null et chaîne vide à l’exécution.
Voir une proposition de correction
La promesse peut tromper l’analyse si le corps ment. Restaurez la garde et ajoutez des tests des entrées invalides, puis vérifiez que les usages contextuels restent contrôlés.
- Garde réelle.
- Promesse exacte.
- Tests des refus.
Contrôle de connaissances
Une annotation phpstan-assert remplace-t-elle le corps de validation ?
Réponse expliquée : Non, elle décrit ce que le corps doit garantir — La promesse doit correspondre à un comportement exécuté.
Cours associé : 05. Réduction de types et assertions honnêtes ↗
Documentation de référence ↗ https://phpstan.org/writing-php-code/narrowing-types
Module 6 / 8 · 90 min
06. Baseline et retrait de dette
Adopter progressivement sans ouvrir une exclusion générale.
Comprendre le mécanisme
Une baseline enregistre des erreurs existantes pour permettre une adoption progressive à un niveau donné. Elle ne corrige pas les défauts et ne doit pas devenir une règle d’ignorance universelle. Son périmètre doit être versionné et relu comme de la dette : catégories, chemins, quantités et plan de retrait. Les erreurs nouvelles doivent rester visibles.
Raisonner et vérifier
Évitez de régénérer automatiquement la baseline à chaque exécution de CI, car une régression pourrait être absorbée. Une suppression doit être justifiée par un faux positif ou une dette connue, avec un périmètre étroit. Après correction, retirez l’entrée devenue inutile et gardez les mécanismes qui signalent les exceptions non pertinentes. La revue doit distinguer amélioration réelle et simple déplacement des diagnostics.
Inventaire de diagnostics
Une baseline décrit des diagnostics existants. Elle ne réécrit pas les comportements du code. Une baseline enregistre des écarts déjà connus sans corriger leur cause. Associez les entrées sensibles à un travail de résolution et conservez la possibilité de retrouver pourquoi elles ont été admises temporairement.
Erreur fréquente à comprendre Une baseline corrige les bugs à l’exécution.
Elle ne réécrit pas les comportements du code.
Nouveaux défauts visibles
Les nouvelles erreurs doivent rester visibles. Elle doit distinguer dette connue et nouvel écart. La CI doit comparer le code à la dette révisée, pas recréer cette dette avant chaque analyse. Introduisez un défaut de laboratoire pour confirmer qu’un diagnostic nouveau fait effectivement échouer le pipeline.
Erreur fréquente à comprendre La baseline doit absorber toute régression nouvelle en CI.
Elle doit distinguer dette connue et nouvel écart.
Régénération encadrée
La régénération doit être revue. Cette pratique peut normaliser chaque nouveau défaut. Une mise à jour d’outil peut modifier les diagnostics et nécessiter une régénération. Examinez le diff et ses raisons ; une hausse silencieuse du nombre d’erreurs masquées demande une explication.
Erreur fréquente à comprendre Régénérer aveuglément avant chaque analyse protège les régressions.
Cette pratique peut normaliser chaque nouveau défaut.
Suppression ciblée
Une suppression doit être étroite et justifiée. Une suppression globale masque la couverture. Préférez un identifiant de diagnostic, un chemin et une justification précis à une expression globale. Une règle très large peut masquer demain une nouvelle erreur dans une zone jusque-là correcte.
Erreur fréquente à comprendre Ignorer tout message est une stratégie de précision.
Une suppression globale masque la couverture.
Exception devenue inutile
La correction doit retirer l’exception devenue inutile. La dette doit diminuer avec les corrections. Quand le code est corrigé, retirez l’entrée associée. Vérifiez le signal d’erreur ignorée non retrouvée si configuré ; il aide à éviter que des suppressions obsolètes restent actives sans propriétaire.
Erreur fréquente à comprendre Une exception ancienne doit être conservée pour toujours.
La dette doit diminuer avec les corrections.
Revue du diff
Le diff de baseline doit être relu. Des motifs élargis peuvent cacher davantage d’erreurs. Lisez les messages, chemins et nombres d’occurrences modifiés. Une petite variation textuelle peut cacher un élargissement important du périmètre ; le nombre total seul ne décrit pas le risque ajouté.
Erreur fréquente à comprendre Un nombre de lignes réduit prouve forcément moins de dette.
Des motifs élargis peuvent cacher davantage d’erreurs.
Exclusions
Les chemins exclus doivent être compris. La propriété du code n’a pas changé. Exclure tout un dossier supprime aussi les futurs diagnostics de ce dossier. Documentez pourquoi le code est hors périmètre et quelle autre vérification couvre ses points d’entrée réels.
Erreur fréquente à comprendre Déplacer un défaut vers un dossier exclu est une correction.
La propriété du code n’a pas changé.
Adoption progressive
Une baseline peut faciliter une montée progressive. Elle peut servir à planifier la réduction de dette. Vous pouvez viser un niveau plus strict en acceptant une dette initiale limitée. Empêchez les ajouts et retirez les entrées à mesure des corrections afin que cette stratégie produise une progression mesurable.
Erreur fréquente à comprendre La baseline impose de ne jamais augmenter le niveau.
Elle peut servir à planifier la réduction de dette.
Faux positif démontré
Le faux positif doit être démontré. Le diagnostic peut révéler un défaut réel. Un diagnostic gênant n’est pas automatiquement faux. Réduisez le cas, vérifiez le contrat de la dépendance et fournissez une fixture prouvant pourquoi le code est sûr avant d’ajouter une suppression.
Erreur fréquente à comprendre Toute erreur gênante est automatiquement un faux positif.
Le diagnostic peut révéler un défaut réel.
Après correction
Les tests restent nécessaires après suppression d’un diagnostic. La suppression ne prouve aucune correction runtime. Une modification de type peut changer un chemin d’erreur ou une conversion. Gardez les tests de comportement concernés ; la disparition du diagnostic ne démontre pas que les sorties métier restent conformes.
Erreur fréquente à comprendre Un ignore dispense de vérifier le comportement.
La suppression ne prouve aucune correction runtime.
Atelier guidé : lire, expliquer et vérifier le code
vendor/bin/phpstan analyse --generate-baseline
vendor/bin/phpstan analyse
La séquence proposée génère une baseline à partir du code courant avant de l’analyser. Elle risque donc d’admettre le défaut même qu’elle devait détecter. Réorganisez la CI pour utiliser la baseline révisée du dépôt et gardez la génération comme opération de maintenance dont le diff est relu.
La baseline n’édite pas le code pour le corriger. Rien ne prouve une réduction du périmètre ignoré. L’analyse statique n’exécute pas toute la suite. Une régénération aveugle peut normaliser de nouveaux écarts.
Travail pratique : Générez une baseline de laboratoire puis introduisez une nouvelle erreur et corrigez une ancienne.
Critères de correction : La nouvelle erreur fait échouer la CI ; l’ancienne exception est supprimée après correction. Comparez le diff de baseline et refusez les motifs globaux ajoutés sans justification.
Exemple commenté
Dette existante documentée → baseline revue
Nouvelle erreur → échec de CI
Correction → retrait de l’exception correspondante
Le cycle protège la progression plutôt qu’un compteur artificiellement toujours vert.
Exercice de mise en pratique
Générez une baseline de laboratoire puis introduisez une nouvelle erreur et corrigez une ancienne.
Voir une proposition de correction
La nouvelle erreur fait échouer la CI ; l’ancienne exception est supprimée après correction. Comparez le diff de baseline et refusez les motifs globaux ajoutés sans justification.
- Baseline revue.
- Pas de régénération aveugle en CI.
- Exceptions retirées après correction.
Contrôle de connaissances
Une baseline corrige-t-elle les bugs enregistrés ?
Réponse expliquée : Non, elle reporte des diagnostics connus — Le code et sa dette restent à traiter.
Cours associé : 06. Baseline et retrait de dette ↗
Documentation de référence ↗ https://phpstan.org/user-guide/baseline
Module 7 / 8 · 90 min
07. Règles personnalisées et limites de sécurité
Automatiser une politique locale sans promettre un audit complet.
Comprendre le mécanisme
Une règle PHPStan personnalisée peut examiner des nœuds et des types pour signaler un motif interdit dans un contexte. Elle doit formuler une propriété précise et être testée avec cas acceptés et refusés. Interdire un appel direct à une fonction legacy peut être utile ; cela ne démontre pas à soi seul l’absence d’injection, de fuite de secrets ou de défaut d’autorisation dans tous les chemins.
Raisonner et vérifier
PHPStan standard n’est pas un analyseur complet de flux de données sensibles pour toutes les vulnérabilités. Des outils spécialisés, des extensions, la revue et les tests de sécurité ont des périmètres complémentaires. Évaluez faux positifs, faux négatifs et coût de maintenance avant de rendre une règle bloquante. Une règle ignorant un wrapper ou un appel dynamique doit l’indiquer dans ses limites.
Propriété contrôlée
Une règle doit exprimer une propriété précise. Une règle locale a un périmètre limité. Définissez précisément si une règle interdit une API, un argument ou un flux dangereux. Un diagnostic doit annoncer ce qu’il établit, sans promettre une sécurité générale à partir d’un motif syntaxique étroit.
Erreur fréquente à comprendre Interdire une fonction prouve toute sécurité applicative.
Une règle locale a un périmètre limité.
Cas admis
Les fixtures doivent inclure du code accepté. Elle doit discriminer selon la politique. Une règle qui bloque tout semble détecter chaque défaut mais empêche aussi le code correct. Ajoutez des fixtures positives et négatives afin de mesurer les deux côtés de sa frontière de décision.
Erreur fréquente à comprendre Une règle refusant tout est toujours correcte.
Elle doit discriminer selon la politique.
Angles morts
Les faux négatifs doivent être documentés. Les chemins non suivis peuvent conserver un risque. Documentez les formes que la règle ne reconnaît pas : appel dynamique, alias ou wrapper. Cette information permet aux réviseurs de compléter l’analyse au lieu de considérer le rapport vert comme une preuve exhaustive.
Erreur fréquente à comprendre Une absence de diagnostic prouve toute absence de vulnérabilité.
Les chemins non suivis peuvent conserver un risque.
Wrappers et indirection
Un wrapper peut échapper à une règle syntaxique naïve. Les capacités de la règle doivent être vérifiées. Un helper peut appeler hash avec un nom d’algorithme reçu par paramètre. Une recherche de md5 comme nom de fonction ne voit pas forcément ce chemin ; réduisez le cas dans une fixture.
Erreur fréquente à comprendre Tout appel indirect est automatiquement compris par toute règle.
Les capacités de la règle doivent être vérifiées.
Flux de données
PHPStan standard n’est pas un audit complet de taint. Le typage ne couvre pas toutes les vulnérabilités. Le typage standard ne suit pas automatiquement toute provenance d’une entrée jusqu’à SQL ou HTML. Utilisez requêtes paramétrées, encodage adapté et, lorsque pertinent, des outils spécialisés avec hypothèses connues.
Erreur fréquente à comprendre Le niveau max suit automatiquement toutes les données sensibles.
Le typage ne couvre pas toutes les vulnérabilités.
Autorisation métier
La revue d’autorisation complète les règles de types. La politique métier demande une vérification dédiée. Une règle syntaxique peut vérifier qu’un appel de contrôle existe sans prouver que son sujet est correct. Testez aussi que l’acteur Bob ne peut modifier l’objet d’Alice avec une référence valide.
Erreur fréquente à comprendre Des types cohérents prouvent tout droit d’objet.
La politique métier demande une vérification dédiée.
Maintenance
Le coût de maintenance d’une règle compte. Les API et hypothèses peuvent évoluer. L’AST et les contrats des bibliothèques peuvent évoluer. Versionnez la règle avec ses fixtures et vérifiez son comportement lors des mises à jour de PHPStan afin d’éviter des exceptions devenues trompeuses.
Erreur fréquente à comprendre Une règle personnalisée reste correcte pour toute version future.
Les API et hypothèses peuvent évoluer.
Diagnostic utile
Un diagnostic doit être exploitable. La localisation et la propriété facilitent une action correcte. Indiquez l’emplacement, le risque précis et une correction possible. Un message vague comme code dangereux encourage les suppressions ; une explication testable aide à corriger la cause.
Erreur fréquente à comprendre Un message sans contexte suffit à toute correction.
La localisation et la propriété facilitent une action correcte.
Stockage de mots de passe
Interdire MD5 ne valide pas tout stockage de mot de passe. D’autres mauvais choix restent possibles. Interdire MD5 laisse possibles un hash rapide différent, un coût inadapté ou des logs contenant le secret. Vérifiez algorithme adaptatif, vérification, rehash et cycle de stockage séparément.
Erreur fréquente à comprendre L’absence de md5 prouve un coût adaptatif approprié.
D’autres mauvais choix restent possibles.
Outils complémentaires
Les outils spécialisés peuvent compléter l’analyse. Les contrôles ont des périmètres complémentaires. Analyse des dépendances, revue de secrets, tests d’injection et contrôle d’exploitation répondent à des risques distincts. Définissez la preuve attendue pour chacun plutôt qu’additionner des logos d’outils sans critère d’acceptation.
Erreur fréquente à comprendre Installer PHPStan rend tous les autres contrôles inutiles.
Les contrôles ont des périmètres complémentaires.
Atelier guidé : lire, expliquer et vérifier le code
<?php
declare(strict_types=1);
$algorithm = 'md5';
$fingerprint = hash($algorithm, 'lab-data');
echo strlen($fingerprint);
L’extrait calcule un condensat MD5 via hash et une variable. Une règle limitée aux appels directs à md5 peut ne rien signaler. Écrivez une fixture pour ce cas, puis précisez le périmètre revendiqué par la règle. Même une détection améliorée ne valide pas tout le cycle des mots de passe.
Ce calcul reste un hash rapide. Le périmètre annoncé ne comprend pas ce motif. Interdire un seul nom de fonction ne couvre pas tous les usages. hash peut calculer cet algorithme.
Travail pratique : Écrivez la spécification d’une règle interdisant un appel legacy dans un module donné. Préparez un wrapper et un appel hors périmètre.
Critères de correction : Définissez les résultats attendus pour chaque fixture et vérifiez les diagnostics. Documentez ce que la règle ne suit pas, puis complétez avec une revue d’usage et des tests de migration.
Exemple commenté
Politique locale : interdire md5 dans le stockage de nouveaux mots de passe
Règle → fixtures positives/négatives → diagnostic → revue des limites
Le contrôle syntaxique local ne remplace pas l’inventaire des usages cryptographiques.
Exercice de mise en pratique
Écrivez la spécification d’une règle interdisant un appel legacy dans un module donné. Préparez un wrapper et un appel hors périmètre.
Voir une proposition de correction
Définissez les résultats attendus pour chaque fixture et vérifiez les diagnostics. Documentez ce que la règle ne suit pas, puis complétez avec une revue d’usage et des tests de migration.
- Propriété précise.
- Fixtures acceptées et refusées.
- Angles morts documentés.
Contrôle de connaissances
Une règle interdisant md5 prouve-t-elle la sécurité de tous les mots de passe ?
Réponse expliquée : Non, coût, stockage et cycle doivent aussi être vérifiés — L’absence d’un motif ne garantit pas tout le système.
Cours associé : 07. Règles personnalisées et limites de sécurité ↗
Documentation de référence ↗ https://phpstan.org/developing-extensions/rules
Module 8 / 8 · 90 min
08. Cycle sécurisé et préparation aux certifications
Relier exigences, implémentation, tests et exploitation.
Comprendre le mécanisme
Les domaines publics CSSLP abordent la sécurité sur le cycle de vie : concepts, exigences, architecture, implémentation, vérification, exploitation et chaîne d’approvisionnement. Un cours PHPStan ne couvre qu’une partie de ces compétences. Une préparation sérieuse associe lecture du plan officiel en vigueur, exercices de raisonnement et preuves de pratique ; elle n’utilise pas des banques de questions divulguées.
Raisonner et vérifier
Construisez une matrice exigence, menace, contrôle, preuve et propriétaire. Les types réduisent certaines erreurs de programmation ; les tests négatifs vérifient le comportement ; la revue examine l’autorisation ; le contrôle de dépendances détecte des risques connus dans son périmètre. La CI doit préserver cette distinction et l’exploitation doit fournir un suivi d’incident et de renouvellement. Un score pédagogique ne constitue ni une certification de personne ni un audit complet du produit.
Exigences vérifiables
Le cycle sécurisé commence dès les exigences. Les choix de conception conditionnent les contrôles possibles. Avant l’implémentation, exprimez la propriété attendue : par exemple aucun client ne lit les factures d’un autre tenant. Déclinez-la en contrôle concret, scénario de refus et preuve conservée avec la release.
Erreur fréquente à comprendre La sécurité commence seulement après le déploiement.
Les choix de conception conditionnent les contrôles possibles.
Repères de préparation
Les domaines publics CSSLP servent de repère de préparation. Le fournisseur officiel définit son processus de certification. Les domaines publics CSSLP permettent d’organiser conception, développement, vérification et exploitation sécurisés. Utilisez les objectifs publiés et des exercices originaux ; une matrice personnelle aide à repérer les domaines peu travaillés.
Erreur fréquente à comprendre Ce cours délivre automatiquement le titre CSSLP.
Le fournisseur officiel définit son processus de certification.
Évaluation indépendante
Un QCM indépendant ne reproduit pas l’examen officiel. La mesure pédagogique a un autre périmètre. Les QCM du site entraînent et mesurent une progression locale. Leur score ne délivre aucun titre officiel et ne reproduit ni le contenu confidentiel ni les conditions administratives d’un organisme certificateur.
Erreur fréquente à comprendre Un score local équivaut nécessairement au seuil officiel.
La mesure pédagogique a un autre périmètre.
Chaîne de preuves
Les preuves doivent relier risque et contrôle. Le volume ne montre pas les propriétés vérifiées. Pour chaque menace, notez exigence, contrôle, test, résultat et propriétaire. Un scanner vert ne suffit pas si son périmètre ne contient pas le composant exposé ou la propriété annoncée.
Erreur fréquente à comprendre Compter les classes suffit à une assurance de sécurité.
Le volume ne montre pas les propriétés vérifiées.
Tests négatifs
Les tests négatifs complètent les tests nominaux. Les frontières doivent être exercées directement. Un scénario nominal prouve qu’un accès autorisé fonctionne. Ajoutez acteur tiers, jeton expiré et entrée malformée en vérifiant l’absence d’effet ; ces refus établissent d’autres frontières que le succès.
Erreur fréquente à comprendre Un succès prouve tous les refus d’accès.
Les frontières doivent être exercées directement.
Chaîne de dépendances
Les dépendances font partie du cycle de risque. La chaîne d’approvisionnement demande ses propres contrôles. Une bibliothèque et son système de build participent à la surface d’attaque. Verrouillez versions, révisez mises à jour et évitez d’exécuter du code non fiable avec les secrets d’une pipeline privilégiée.
Erreur fréquente à comprendre Un code bien typé rend toute dépendance sûre.
La chaîne d’approvisionnement demande ses propres contrôles.
Après déploiement
L’exploitation inclut surveillance et réponse à incident. Le système évolue et peut subir des incidents. Définissez surveillance, triage et réponse à incident avant la panne. Les journaux doivent être utiles sans exposer les credentials ; les procédures de rotation et restauration doivent être exercées.
Erreur fréquente à comprendre La CI verte supprime tout besoin de surveillance.
Le système évolue et peut subir des incidents.
Lacunes déclarées
Un dossier doit annoncer les lacunes restantes. L’assurance doit rester proportionnée aux preuves. Une propriété non testée doit rester visible dans le dossier. Assignez un traitement et un délai au risque résiduel ; masquer l’absence de preuve derrière un score élevé empêche une décision éclairée.
Erreur fréquente à comprendre Une lacune non documentée constitue une garantie.
L’assurance doit rester proportionnée aux preuves.
Questions originales
Les questions confidentielles ne sont pas nécessaires à la préparation. Les plans publics et exercices originaux suffisent à guider l’étude. Préparez-vous avec documentation publique, cas pratiques et questions authored pour le cours. L’apprentissage doit porter sur les mécanismes et leur application, sans rechercher de banques confidentielles d’examen officiel.
Erreur fréquente à comprendre Une préparation sérieuse exige des banques divulguées.
Les plans publics et exercices originaux suffisent à guider l’étude.
Responsabilité du risque
Chaque risque doit avoir un traitement et un propriétaire. Le suivi opérationnel ne se résume pas au score. Un risque sans propriétaire reste facilement sans suite. Désignez qui accepte, corrige ou surveille chaque risque et précisez le signal qui doit déclencher une nouvelle évaluation.
Erreur fréquente à comprendre Un score global remplace toute responsabilité de suivi.
Le suivi opérationnel ne se résume pas au score.
Atelier guidé : lire, expliquer et vérifier le code
# Périmètre de l’exercice : seule cette commande est exécutée.
script:
- vendor/bin/phpstan analyse --no-progress
La pipeline d’exemple exécute uniquement l’analyse statique. Demandez quelle preuve manque pour l’isolation des réservations, puis écrivez un test à deux acteurs sur le même objet. Associez ce test à une menace explicite et à un responsable, sans attribuer au typage une propriété qu’il ne mesure pas.
Le bloc existe dans l’extrait. La politique d’objet demande des tests et une revue dédiés. La commande le montre bien. Le chemin est explicite.
Travail pratique : Établissez un dossier de préparation pour l’API de synthèse : trois risques, contrôles associés, preuves et lacunes restantes.
Critères de correction : Joignez configuration versionnée, résultat d’analyse, tests de refus, revue de droits et procédure d’incident. Reliez chaque pièce à une exigence et à un domaine du plan public. Consultez le fournisseur de certification pour ses conditions et modalités en vigueur.
CI : exécuter un fork sans lui donner les secrets de déploiement
pull_request_target s’exécute dans un contexte qui peut disposer de privilèges du dépôt cible. Si le workflow checkout le commit non fiable d’un fork puis lance ses tests, ce code peut contenir des scripts capables de lire secrets et credentials du job.
Séparez les tests de code non approuvé dans un contexte sans secrets et sans droits d’écriture. Réservez publication et déploiement à une chaîne de confiance explicite. La séparation doit aussi considérer les artefacts transmis : un job privilégié ne doit pas exécuter aveuglément un script ou un binaire produit par le job non fiable.
Testez les permissions effectives et les événements autorisés avec des données factices. Réduisez GITHUB_TOKEN aux besoins du job et épinglez les dépendances d’action selon votre politique. Le masquage de logs ne constitue pas une frontière de confidentialité contre un programme qui possède déjà le secret et peut l’envoyer par un autre canal.
Points de vigilance : Le code peut exfiltrer un secret autrement que par son affichage littéral dans les logs. Le nom du workflow et l’extension du fichier ne créent pas de frontière de confiance. Un délai court laisse le temps de détourner un secret ou une permission. La séparation empêche le code non approuvé d’hériter de privilèges de déploiement ; contrôler aussi les artefacts transmis.
Documentation de référence ↗
Migration Strangler : une seule implémentation propriétaire de l’effet
Une extraction progressive laisse le monolithe et le nouveau service coexister. Définissez une frontière fonctionnelle et un contrat stable, puis routez une cohorte maîtrisée vers une seule implémentation active pour chaque intention de paiement.
La réversibilité doit porter sur les demandes futures et les états que l’ancienne implémentation sait encore comprendre. Elle ne signifie pas pouvoir annuler un débit externe déjà accepté. Évitez un double appel PSP pour comparer les sorties ; utilisez tests de contrat ou comparaison sans effet lorsque cela est réellement possible.
Définissez propriétaire de l’écriture, identité d’opération, compatibilité des messages et procédure de rapprochement pendant la transition. Testez bascule partielle et retour de routage avec états en cours. Les métriques doivent détecter divergence et erreur sans exposer les credentials. Une migration réussie retire progressivement les anciens chemins après preuve ; laisser deux producteurs d’effets en concurrence sans règle claire ajoute une nouvelle source de doublons.
Points de vigilance : La migration incrémentale exige un routage maîtrisé et un propriétaire clair de chaque effet irréversible. La première réponse ne supprime pas l’autre débit éventuellement exécuté. La suppression préalable retire le filet de retour demandé. Des écritures et décisions concurrentes sans propriétaire compliquent les invariants et le retour arrière.
Documentation de référence ↗
Exemple commenté
Exigence → conception → code → analyse + tests + revue → déploiement → surveillance
Chaque étape conserve ses preuves et ses limites.
Le parcours rejoint des domaines publics de compétences sans prétendre reproduire l’examen officiel.
Exercice de mise en pratique
Établissez un dossier de préparation pour l’API de synthèse : trois risques, contrôles associés, preuves et lacunes restantes.
Voir une proposition de correction
Joignez configuration versionnée, résultat d’analyse, tests de refus, revue de droits et procédure d’incident. Reliez chaque pièce à une exigence et à un domaine du plan public. Consultez le fournisseur de certification pour ses conditions et modalités en vigueur.
- Couverture partielle annoncée.
- Questions originales.
- Preuves sur tout le cycle.
Contrôle de connaissances
Un succès au QCM du site délivre-t-il le titre CSSLP ?
Réponse expliquée : Non, il s’agit d’une évaluation pédagogique indépendante — Le fournisseur officiel définit son processus et ses conditions.
Cours associé : 08. Cycle sécurisé et préparation aux certifications ↗
Documentation de référence ↗ https://www.isc2.org/certifications/csslp/csslp-certification-exam-outline