PHPStan

par

dans

La majorité des informations qui suivent sont directement issues du site officiel de PHPStan.

Présentation de PHPStan

Quelle est l’utilité de PHPStan ?

PHPStan est un outil open-source d’analyse statique du code source PHP et est lui-même codé en PHP. Il a pour but de parcourir un code PHP sans l’exécuté afin d’identifier des anomalies. Il peut être comparé à un compilateur qui a pour but de compiler un programme dans son intégralité et de signaler des erreurs à cet instant plutôt qu’au moment de l’exécution. Car effectivement, PHP n’étant pas compilé, les erreurs surviennent uniquement lorsque le code est exécuté.

PHPStan permettra donc de lire tout votre code et de vous signaler des erreurs sans que vous ayez à le tester intégralement, que ce soit par des tests automatisés ou manuels. Attention toutefois, cela ne doit en aucun cas vous empêcher d’en coder. PHPStan ne vérifie pas la logique métier de votre code.

Que contrôle PHPStan ?

PHPStan dispose de différents niveaux de contrôles allant de 0 à 9. Selon le niveau sélectionné, tous les contrôles ne seront pas appliqués. Chaque niveau sélectionné applique bien évidemment en cascade les contrôles des niveaux inférieurs. Par défaut c’est le niveau 0, le moins strict, qui est appliqué. Cela permet de monter de niveau au fur-et-à-mesure que l’on traite les anomalies.

Voici les éléments actuellement contrôlés par PHPStan :

  • Niveau 0
    • L’existence des classes utilisées dans les instructions instanceof, catch, dans le typage des arguments et retour de fonctions, etc.
    • L’existence et l’accessibilité (via les mots-clés public, protected et private) des méthodes appelées, notamment sur l’objet $this.
    • Le nombre d’arguments passés aux méthodes.
    • Les variables non définies.
  • Niveau 1
    • Variables non définies.
    • L’existence des méthodes magiques utilisés et propriétés (via __cal et __get).
  • Niveau 2
    • L’existence des méthodes utilisées, pas uniquement sur l’objet $this.
    • Vérification des PHPDocs.
  • Niveau 3
    • Le type de de donnée retourné par une méthode par rapport au type de retour indiqué dans sa déclaration.
    • L’assignation à une propriété d’un type de donnée différent de celui indiqué dans sa déclaration.
  • Niveau 4
    • La présence de code inutile comme des instructions if / instanceof / elseif / else etc. qui retournent toujours false ou encore la présence de code après des instruction return.
  • Niveau 5
    • Le type des arguments passées aux méthodes.
  • Niveau 6
    • L’oublie de définition de types.
  • Niveau 7
    • L’incohérence dans des unions de plusieurs types.
  • Niveau 8
    • L’appel de méthodes et l’accès à des propriétés à partir d’éléments nullables.
  • Niveau 9
    • L’usage du type mixed. Notamment pour s’assurer qu’on passe une telle variable à un autre type lui aussi mixed.

Autres contrôles par encore classés :

  • L’existence et l’accessibilité (via les mots-clés public, protected et private) des propriétés auxquelles le code accède.
  • Le nombre d’arguments passés aux méthodes.
  • Le nombre d’arguments dans un certain nombre de méthodes natives (sprintf par exemple).
  • L’existence des variables utilisées dans le scope d’exécution (fonction, boucle, etc.).
  • L’existence des constantes utilisées.
  • Les typages forcés inutilement en cast (via (string) par exemple).
  • Les comparaisons strictes via === et !== lorsque les opérandes ne sont pas du même type.

Installation et utilisation de PHPStan

Pré-requis

  • Dans sa version actuelle, la 1.0, PHPStan nécessite au minimum PHP 7.1 pour fonctionner.
  • Avoir Composer. Facultatif pour l’installation de PHPStan, mais indispensables pour installer ses extensions.

Installation

L’installation s’effectue simplement via la commande Composer suivante :

composer require --dev phpstan/phpstan

Si nécessaire, il faudra ajouter des extensions selon ce qui est utilisé par votre projet. La liste des extensions est disponible sur la documentation officielle : Extensions PHPStan. En voici quelques unes intéressantes :

  • PHPUnit
  • Doctrine
  • Symfony

Utilisation

Pour effectuer une analyse du code il faut utiliser la commande analyse et indiquer le ou les répertoires que PHPStan doit parcourir.

# Analyse de 2 répertoires
vendor/bin/phpstan analyse src tests

Spécifier le niveau de contrôle avec l’option -l ou --level

vendor/bin/phpstan analyse -l 6 src

Appliquer le plus haut niveau de contrôle (9 aujourd’hui, mais peut-être plus demain) avec --level max

vendor/bin/phpstan analyse --level max src

Le niveau a appliquer et les chemins des fichiers à analyser peuvent être indiqués dans le fichier de configuration de PHPStan ainsi :

parameters:
	level: 6
	paths:
		- src
		- tests

Utilisation à travers un fichier de configuration

Plutôt que de fournir un grand nombre d’arguments à la ligne de commande, il est possible de simplement indiquer un fichier de configuration qui contient tout le paramétrage.

vendor/bin/phpstan analyse -c phpstan.neon

La gestion des priorités pour le paramétrage et la suivante :

  1. Si un fichier de configuration est fourni dans la commande, il est utilisé.
  2. En l’absence de fichier de configuration dans la commande, si un fichier phpstan.neon existe dans le répertoire, il est utilisé.
  3. Sinon, si un fichier phpstan.neon.dist existe dans le répertoire, il est utilisé.

Format de sortie

Plusieurs formats de sortie sont proposés et peuvent être spécifié dans la commande ainsi :

# Exemple avec une sortie au format json
vendor/bin/phpstan analyse --error-format=json src

Les formats disponibles sont les suivants :

FormatExplications
tableFormat par défaut défaut.
Regroupe les erreurs par fichiers en indiquant pour chaque erreur la ligne concernée.
rawAffiche une ligne par erreur avec le chemin du fichier, le numéro de la ligne dans le fichier et une description de l’erreur.
checkstyleCreates a checkstyle.xml compatible output. Note that you’d have to redirect output into a file in order to capture the results for later processing.
jsonCreates minified .json output without whitespaces. Note that you’d have to redirect output into a file in order to capture the results for later processing.
prettyJsonCreates human readable .json output with whitespaces and indentations. Note that you’d have to redirect output into a file in order to capture the results for later processing.
junitCreates JUnit compatible output. Note that you’d have to redirect output into a file in order to capture the results for later processing.
githubCreates GitHub Actions compatible output.
gitlabCreates format for use Code Quality widget on GitLab Merge Request.
teamcitySortie pouvant être consultée dans TeamCity.

La documentation officielle explique également comment créer un format personnalisé.

Indiquer à PHPStan où localiser les classes / fonctions / constantes etc. utilisées dans le code à analyser

Afin de ne pas signaler de nombreuses erreurs qui n’en seraient pas, PHPStan a besoin de savoir où se situent certains éléments utilisés dans votre code. Par exemple, si vous lancez une analyse de votre répertoire src dans lequel vous utilisez des classes situées dans le répertoire vendor géré par Composer, PHPStan n’en aura pas connaissance et signalera des erreurs pour usage de classes inconnues.

Pour le coup, PHPStan sait accéder au répertoire vendor, mais cela permet de bien comprendre la problématique. Vous pourriez avoir du code utilisé dans le répertoire à analyser, mais déposer dans un autre répertoire.

Par défaut, PHPStan prend en compte les répertoires suivants :

  • Le ou les répertoires dont on demande l’analyse explicitement dans la ligne de commande.
  • Le ou les répertoires indiqués dans un fichier de configuration de PHPStan.
  • Les dépendances Composer du projet.

Exemple 1 : Indiquer des fichiers utilisés par votre code mais ne devant pas être analysés et n’étant pas dans les dépendances Composer

Si votre projet utilise du code de fichiers qui ne sont ni dans les répertoires analysés ni dans le répertoire des dépendances Composer et que ces fichiers ne doivent pas être analysés par PHPStan, il faut les lui indiquer. Il est possible d’indiquer des fichiers unitairement et des répertoires ainsi :

pparameters:
    scanFiles:
      - File.class.php
    scanDirectories:
      - third_classes
      - other_classes

Note : Indiquez les chemins relatifs basés sur le répertoire du fichier de configuration de PHPStan.

À l’inverse, si des fichiers / répertoires sont présents dans ceux à analyser mais ne doivent pas l’être, il est possibles de les exclure ainsi :

pparameters:
    excludePaths:
      - vendor

Exemple 2 : Un fichier de définition de constantes globales

Si votre projet dispose par exemple d’un fichier de définition de constantes globales situé ailleurs que dans les répertoires analysés, vous devez indiquer à PHPStan l’emplacement de ce fichier afin de ne pas avoir une multitude d’erreurs de constantes non définies. Un tel fichier doit être ajouté au fichier de configuration de PHPStan ainsi :

parameters:
    bootstrapFiles:
        - constants.php

Autres cas

Il est également possible d’indiquer dans le fichier de configuration :

  • Le chemin vers un autoloader personnalisé.
  • Les alias de classes si votre projet utilise un syntaxe PHP telle que class_alias(\Foo::class, 'Bar');.

Ignorer certaines erreurs

La documentation officielle fournie quelques exemples probants d’erreurs que l’on voudrait pouvoir ignorer afin qu’elles ne « polluent » pas les rapports et que ceux-ci soient uniquement constitués d’erreurs à traiter. Voici quelques exemples :

  • Une erreur nécessitant un refactoring important du code qui ne peut pas être réalisé dans l’immédiat.
  • Un code / une syntaxe non reconnue par PHPStan et nécessitant que l’outil évolue ou qu’une extension lui soit ajoutée.
  • Un bug de PHPStan devant être corrigé mais dont on ne peut attendre le correctif pour avoir un rapport probant.

Il y a plusieurs façons d’indiquer à PHPStan d’ignorer des erreurs :

  • En utilisant PHPDocs directement dans le code source.
  • En complétant le fichier de configuration de PHPStan.
  • En excluant des fichiers entiers.

Ignorer du code grâce à PHPDocs

PHPStan propose deux syntaxes passant par un commentaire PHP. L’une permet d’ignorer la ligne courante, on place donc le commentaire sur la même ligne, l’autre permettant d’ignorer la ligne PHP qui la suit directement. Les commentaires mono-ligne comme multi-lignes peuvent être utilisés.

/** @phpstan-ignore-next-line */
echo $foo;

echo $foo; /** @phpstan-ignore-line */

// @phpstan-ignore-next-line
echo $foo;

echo $foo; // @phpstan-ignore-line

Ignorer du code grâce au fichier de configuration

Le fichier de configuration de PHPStan peut être complété d’une section ignoreErrors dans laquelle peuvent être ajoutées des messages d’erreurs / chemins de fichiers et répertoire à ignorer. Les messages peuvent contenir des expressions régulières ce qui permet de pouvoir facilement en une ligne d’ignorer de multiples erreurs.

Ignorer du code en excluant des fichiers

Le fichier de configuration de PHPStan permet d’indiquer des fichiers et répertoire à ignorer dans leur intégralité.