Aller au contenu principal

Phan

Un second analyseur statique pour détecter les erreurs de typage dans du code PHP, sans l'exécuter

Notions théoriques

Phan est, comme PHPStan, un outil d'analyse statique : il inspecte le code source PHP sans l'exécuter et signale les erreurs potentielles avant même que le programme ne tourne. Il détecte notamment les incompatibilités de types, les appels à des méthodes ou fonctions inexistantes, et les variables non définies.

Pourquoi utiliser Phan ?

  • Trouver des bugs de typage sans avoir à les déclencher manuellement
  • Vérifier que le code respecte les types déclarés dans les signatures de fonctions
  • Détecter des appels à des méthodes ou classes qui n'existent pas
  • Compléter les tests automatisés, comme PHPStan

Phan et PHPStan : deux outils complémentaires

Phan et PHPStan sont tous les deux des outils SAST (analyse statique) dédiés à PHP. Ils poursuivent le même objectif — détecter des erreurs de type avant l'exécution — mais avec des moteurs d'analyse différents. Il est courant de n'utiliser qu'un seul des deux, mais rien n'empêche de les combiner sur un même projet : chacun peut détecter des erreurs que l'autre ne signale pas.

Phan a deux particularités notables :

  • Une inférence de types poussée : il déduit le type des variables en suivant leur usage dans le code, même en l'absence d'annotations explicites
  • Un mode polyfill : Phan s'appuie normalement sur l'extension PHP ast pour analyser le code. Si cette extension n'est pas installée, Phan peut fonctionner en mode polyfill, plus lent mais sans dépendance à une extension native
info

Phan a déjà été présenté dans la partie DevSecOps consacré à l'analyse de code SAST/DAST, comme exemple d'analyseur statique spécialisé pour PHP. Cette séance approfondit son installation et son usage.

Installation

composer require --dev phan/phan

Fichier de configuration .phan/config.php

Phan se configure via un fichier PHP placé dans un dossier .phan/ à la racine du projet :

<?php

return [
'directory_list' => [
'src',
],
'exclude_analysis_directory_list' => [
'vendor/',
],
];
  • directory_list : les dossiers que Phan doit analyser
  • exclude_analysis_directory_list : les dossiers à ignorer (les dépendances externes, notamment)

Lancer l'analyse

vendor/bin/phan

Exemple de mise en application

Considérons cette fonction de notre jeu, qui calcule les dégâts infligés par une attaque :

function calculateDamage(int $strength, int $weaponPower): int
{
return $strength + $weaponPower;
}

echo calculateDamage("quarante-cinq", 10);

En exécutant vendor/bin/phan, l'outil signale une incompatibilité de type :

test.php:5 PhanTypeMismatchArgument Argument 1 ($strength) is
string but calculateDamage() takes int

Phan a détecté, sans exécuter le script, que la chaîne "quarante-cinq" est passée à un paramètre déclaré int. La correction consiste à passer une véritable valeur entière.

Test de mémorisation/compréhension


Que fait Phan ?


Quel est le point commun entre Phan et PHPStan ?


À quoi sert le mode polyfill de Phan ?


Quelle commande installe Phan dans un projet ?


Où se trouve le fichier de configuration de Phan ?


Quelle commande lance l'analyse Phan ?


Dans le fichier de configuration, à quoi sert la clé `directory_list` ?



TP pour réfléchir et résoudre des problèmes

Configurez Phan sur le code de votre jeu et corrigez l'erreur de typage détectée

Étape 1 : Créez le fichier .phan/config.php pour analyser le dossier src/ et exclure le dossier vendor/.

<?php

return [
'directory_list' => [
'src',
],
'exclude_analysis_directory_list' => [
'vendor/',
],
];

Étape 2 : Corrigez l'appel à calculateDamage() qui provoque une erreur PhanTypeMismatchArgument en lui passant un entier au lieu d'une chaîne de caractères.


Bonne pratique - Typer systématiquement les paramètres et les valeurs de retour

Plus les fonctions déclarent des types précis pour leurs paramètres et leur valeur de retour, plus Phan (et PHPStan) peuvent détecter d'erreurs tôt. Un code non typé prive ces outils d'une grande partie de leur utilité.

📌 Une solution