
Partager:
Acteur de formation avec une thèse sur la comédie, je suis venu au développement PHP par le biais de la scène des rencontres. Vous pouvez me trouver en train de parler et d'écrire sur la technologie, ou de jouer/acheter des disques bizarres de ma collection de vinyles.
Nettoyer ! Nettoyer votre application PHP avec PHPStan
Depuis que je suis développeur PHP, la façon dont nous écrivons et livrons le code a changé de façon spectaculaire. Au début de Symfony et Zend Framework l'outil PHP-FIG n'existait pas et les normes de codage étaient laissées à la discrétion de celui qui les écrivait. Au fil des années, nous avons vu l'adoption généralisée des normes de normes PSRles outils d'analyse statique solides comme le roc ont été quelque peu inégaux. Jusqu'à présent, avec la sortie de la version 1.0 de de la version 1.0 de PHPStan. Célébrons cet événement en passant en revue quelques-unes de ses fonctionnalités !
Les langages compilés, votre chasseur de bogues préventif
L'un des grands avantages de l'utilisation d'un langage compilé tel que Java ou le C# est que la compilation échouera complètement si votre code n'est pas typesafece qui permet d'appliquer des normes (bien que ce soit facile pour moi de dire cela car il n'est pas 2 heures du matin, avec mon 10ème café de la nuit). Avec PHP étant un langage interprété, nous n'avons pas le même luxe.
Interprété comme compilé : CI + outillage
Grâce à la quantité d'outils DevOps disponibles pour le développement web moderne et l'analyse statique, le fait est que nous disposons des mêmes outils, mais par des moyens différents. Dans ce cas, je ne peux pas préconiser combien Je vous recommande d'avoir un environnement similaire à celui que je vais vous présenter. Alors, pourquoi voudriez-vous cet outil ? Prenons un exemple.
Le scénario
Il est courant d'essayer de choisir un thème amusant ou applicable à ce que vous écrivez lorsqu'il s'agit d'outils comme celui-ci. Mais pour cet article, je vais vous présenter un scénario que j'ai personnellement rencontré à maintes reprises dans des environnements d'agence :
"A l'aide ! Quelqu'un d'autre a construit mon application PHP et j'ai besoin de quelqu'un pour la sauver et prendre en charge sa maintenance parce que les fonctionnalités X/Y/Z doivent être construites, mais les fonctionnalités A/B/C ne fonctionnent même pas bien !"
Reprendre la base de code ou le projet de quelqu'un d'autre est toujours une loterie. Si vous le reprenez parce qu'il a besoin de nouvelles fonctionnalités et qu'il est déjà criblé de dettes techniques, vous savez que vous devez régler ce problème avant de toucher à quoi que ce soit d'autre. Pire encore, beaucoup de ces projets (d'après mon expérience) ont tendance à arriver sans aucun test pour auto-documenter le code. Prenons un exemple classique, que j'ai vu à maintes reprises :
$someData = \MyNamespace\MyORM\MyRepository::findAllBySomething(SOMETHING);
foreach ($someData as $myEntity) {
$myEntity->doTheThing();
}
Vous n'avez pas écrit cette classe d'entité ou la méthode de dépôt. Elles n'ont pas de typehints parce qu'elles ont été écrites à l'origine en PHP5.3, ou que le développeur n'en a pas utilisé. C'est bien si votre ORM retourne un tableau des mêmes entités, mais un bug, un résultat nul dans la valeur de retour de findAllBySomething() et doTheThing() provoquera une erreur fatale.
Il est temps de définir PHPStan sur elle.

Connaître sa stratégie
Bien qu'il soit facile de dire "utilisez PHPStan", si vous avez une application héritée ou lourdement endettée, vous aurez besoin d'une stratégie plutôt que de simplement lancer des choses pour voir ce qui se passe. Tout d'abord, vous devez vous familiariser avec les niveaux de règles.
Niveaux de règles
PHPStan est structuré pour fonctionner avec des niveaux de règles donnés, numérotés de 0 à 9 :
contrôles de base, classes inconnues, fonctions inconnues, méthodes inconnues appelées sur
$thisnombre erroné d'arguments transmis à ces méthodes et fonctions, variables toujours indéfinieséventuellement des variables indéfinies, des méthodes magiques inconnues et des propriétés sur les classes avec
__callet__getles méthodes inconnues vérifiées sur toutes les expressions (et pas seulement
$this), validation des PHPDocsles types de retour, les types attribués aux propriétés
vérification de base des codes morts - toujours faux
instanceofet autres vérifications de type, brancheselsebranches mortes, code inaccessible après le retour ; etc.vérifier les types d'arguments transmis aux méthodes et aux fonctions
signaler les indications de type manquantes
signaler les types d'union partiellement erronés - si vous appelez une méthode qui n'existe que pour certains types dans un type d'union, le niveau 7 commence à le signaler ; autres situations éventuellement incorrectes
rapport sur l'appel de méthodes et l'accès à des propriétés sur des types nullables
être strict sur le type de
mixedla seule opération autorisée est de le transmettre à un autre utilisateur.mixed
C'est pourquoi votre stratégie est importante. Si vous avez un projet écrit par quelqu'un d'autre et que vous lancez le programme PHPStan au niveau 9, vous risquez d'être submergé par les résultats qu'il produit. Tout est cassé ! Pour remanier, je suggérerais ce qui suit :
Fixez-vous des étapes pour chaque niveau identifié et commencez modestement.
L'investissement à long terme finira par porter ses fruits (nous parlerons bientôt des pipelines), mais fixez le niveau maximal que vous êtes prêt à atteindre pour classer la "correction de la dette technologique" dans votre propre "définition de ce qui est fait"
Un bon objectif de facto pour un projet patrimonial est d'atteindre le niveau 6 de la règle. C'est à ce stade que votre base de code peut passer d'un état "dangereux" à un état "correct". Cela ferait du niveau de règle 6 votre ligne de base).
C'est très important: s'assurer d'allouer du temps (sprints, tickets Jira décomposés pour les masochistes) pour corriger ce que PHPStan signale à chaque niveau de règle. Réparer la dette technique n'est pas facile dans de nombreux cas, et vous n'avez aucune idée du type de défauts logiques liés au domaine d'activité de votre application.
Lors de la définition des objectifs incrémentaux pour les niveaux de règle, veillez à mettre en place votre pipeline avant de valider les modifications afin de ne pas introduire de nouvelles odeurs de code lors de la refonte. Pour mettre en place votre pipeline, vous devrez établir votre ligne de baseque nous allons aborder.
Pipeline
Dans le monde de DevOps, il existe une quantité quelque peu écrasante d'options d'outils disponibles pour résoudre vos problèmes. Dans le cas présent, je ne propose qu'une seule approche, mais elle est moins complexe que les autres options disponibles. Une fois que vous avez établi votre stratégie, il est temps de configurer votre pipeline de sorte que nous n'engagions pas de nouveau code qui ne soit pas d'abord passé par PHPStan.
Obstacles à la défense : local ou côté serveur
J'aime mettre en place des outils pour éliminer toute possibilité de point de défaillance unique et, en conséquence de ce cynisme, je recommande vivement que vous exécutiez votre analyse statique à la fois sur les machines des développeurs locaux ainsi que sur les vérifications CI côté serveur dans votre référentiel.
Locale
Compositeur + PHPStan
Tout d'abord, vous devez installer PHPStan dans votre projet. Nous allons utiliser composer pour cela, en partant du principe que votre code hérité utilise la gestion de paquets. Si ce n'est pas le cas, vous pouvez installer composer et utiliser composer init pour créer un nouveau projet.
Pour installer PHPStan, exécutez la procédure suivante :
Nous ajoutons --dev car nous n'en avons pas besoin pour la production (en théorie !).
Configuration : établir la base de référence
Il s'agit d'une fonctionnalité très intéressante de PHPStan. Votre ligne de base établit le "point zéro" de votre application, de sorte que toutes les erreurs actuelles qui existent dans le niveau de règle de votre choix sont ignorées jusqu'à ce que vous décidiez de les traitermais en même temps peut imposer un niveau de règle pour toute nouvelle modification apportée.. Une approche raisonnable, telle que décrite dans la stratégie, consisterait à fixer une ligne de base au niveau de règle 6 :
Tout nouveau code intégré au projet devrait être de niveau 6.
Vous pouvez ensuite fixer les objectifs en matière de dette technologique pour les niveaux inférieurs, tels qu'ils sont définis dans vos objectifs stratégiques.
Pour créer votre ligne de base, exécutez la procédure suivante :
Votre configuration de base est maintenant définie dans le fichier spécifié (phpstan.neon), ce qui permet d'obtenir un aperçu détaillé des erreurs par fichier.
Maintenant, vous voulez que PHPStan empêche les commits sur votre dépôt avant que avant qu'ils ne soient poussés vers votre source. Pour cela, nous utilisons les crochets Git.
Crochets Git
Il m'a fallu des années pour réaliser que git installe en standard des hooks dans un nouveau dépôt git sur git init. Vous pouvez en savoir plus sur les hooks git ici. Nous allons éditer le pre-commit . Tant que vous n'avez pas touché aux hooks dans votre projet, vous pouvez activer le hook pre-commit en le renommant - exécutez ceci à partir de la racine de votre projet :
Ouvrez maintenant le fichier, supprimez le contenu et copiez ce qui suit :
Maintenant que vous avez activé pre-commitPHPStan se déclenchera avant chaque livraison et analysera par rapport à la ligne de base pour tout nouveau fichier qui a été modifié dans le commit git. Plus de code commit malodorant !
Il se peut que vous souhaitiez ajuster le déclencheur de la ligne de commande lorsque vous passez à un niveau supérieur. Ainsi, lorsqu'il doit être modifié (ou que vous souhaitez activer d'autres fonctionnalités de PHPStan), modifiez les arguments de la ligne de commande analysisResult=$(vendor/bin/phpstan analyse $gitDiffFiles) Les arguments de la ligne de commande.
Côté serveur
Plus vous pouvez défendre votre code, mieux c'est. L'exécution de PHPStan côté serveur après une poussée de votre code dans le cadre de votre intégration continue est un indispensable. Pour cet exemple, nous allons utiliser les Actions Github, mais gardez à l'esprit que vous pouvez configurer ceci avec le même niveau de fonctionnalité dans CircleCI, Bitbucket Pipelines, Gitlab CI/CDou Jenkins. Voici un exemple de flux d'actions mis en place sur Github, construisant votre code avec un serveur Ubuntu Ubuntu :
---
name: build
on: [ push, pull_request ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
name: Build example
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.0
extensions: json, mbstring
coverage: pcov
env:
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Run PHPStan
run: vendor/bin/phpstan analyse .La commande sous "Exécuter PHPStan" peut être configurée selon vos besoins de la même manière que vous pouvez configurer la commande lors de l'exécution locale de PHPStan. J'ai écrit ce flux de travail pour exécuter PHPStan à un niveau par défaut sur tous les fichiers du projet (ce flux de travail n'a pas encore été lancé). composer n'a pas encore été lancé, il n'y aura donc pas l'étape inutile et inefficace de l'exécuter sur votre dossier vendor ). Je recommande donc d'utiliser une configuration qui définit le niveau de règle de l'ensemble du projet.
Votre projet a maintenant une stratégie pour nettoyer votre code, et des pipelines pour arrêter l'apparition de nouveaux bugs dans les commits tout en effectuant une analyse par rapport à la ligne de base pour tout le code existant. C'est ce type de configuration qui peut vous donner beaucoup plus de confiance pour vous engager dans le projet tout en vous donnant des indications sur les domaines probables qui ont besoin d'être remaniés pour éliminer la dette technologique.
Dernier point, mais non des moindres : l'analyse statique et les tests
Je le dis haut et fort, surtout pour les personnes qui se trouvent au fond de la salle : PHPStan et tout autre outil d'analyse statique ne remplacent pas vos tests ! La façon dont je conçois son utilisation est qu'une suite de tests et PHPStan se complètent dans l'évaluation de la qualité de votre code.
Il est faux de croire que l'on n'a que peu ou pas besoin d'une suite de tests. La chose la plus importante ici est que l'analyse statique ne peut pas tester la logique de votre domaine. Bien que cette affirmation puisse sembler évidente, il convient de noter qu'elle peut prêter à confusion, car PHPStan peut éliminer la nécessité de certains tests. Un exemple de ceci serait un instanceOf qui affirme qu'une classe créée est le résultat final d'un processus. PHPStan peut supprimer cette exigence, car il fournit l'analyse nécessaire pour éliminer ce bogue potentiel, mais il n'a pas pas la logique du domaine requise au préalable - c'est ce que vous faites. devez c'est ce que vous devez tester.
Et n'oubliez pas qu'il existe des alternatives !
Vous avez essayé ? Vous n'êtes pas très enthousiaste ? Chacun a ses préférences, et même si je ne taris pas d'éloges à l'égard de Ondřej pour son travail sur PHPStan, il est bon de noter qu'il existe plusieurs autres outils qui font le même travail ou qui peuvent être utilisés en conjonction avec PHPStan :
Remerciements
Nous remercions tout particulièrement Ondřej Mirtes pour ses conseils et tout le travail qu'il a accompli pour mettre au point ce formidable outil.
Partager:
Acteur de formation avec une thèse sur la comédie, je suis venu au développement PHP par le biais de la scène des rencontres. Vous pouvez me trouver en train de parler et d'écrire sur la technologie, ou de jouer/acheter des disques bizarres de ma collection de vinyles.