NoVerify: un linter PHP qui fonctionne rapidement

Il existe de bons utilitaires d'analyse statique pour PHP: PHPStan, Psalm, Phan, Exakat. Les linters font bien leur travail, mais très lentement, car presque tous sont écrits en PHP (ou Java). Pour un usage personnel ou un petit projet, c'est normal, mais pour un site avec des millions d'utilisateurs, c'est un facteur critique. Un linter lent ralentit le pipeline CI et rend impossible son utilisation en tant que solution pouvant être intégrée dans un éditeur de texte ou un IDE.



Un site avec des millions d'utilisateurs est VKontakte. Développement et ajout de nouvelles fonctions, test et correction de bugs, revues - tout cela devrait aller vite, dans des conditions de délais serrés. Par conséquent, un bon et rapide linter qui peut vérifier la base de code pour 5 millions de lignes en 5-10 secondes est une chose irremplaçable. 

Il n'y a pas de linters appropriés sur le marché, donc Yuri Nasretdinov (tu gères) de VKontakte a écrit son aide aux équipes de développement - NoVerify. Il s'agit d'un linter pour PHP, qui est écrit en Go. Il fonctionne 10 à 30 fois plus rapidement que ses homologues, peut trouver quelque chose que PhpStorm ne prévient pas, étend facilement et s'intègre bien dans des projets qui n'ont jamais entendu parler de l'analyse statique auparavant. Iskander Sharipov

parlera de ce linter . Sous le chat: comment choisir un linter et préférez écrire le vôtre, pourquoi NoVerify est si rapide et comment il est organisé à l'intérieur, pourquoi il est écrit en Go, ce qu'il peut trouver et comment il se développe, quels compromis vous avez dû faire pour lui et ce qui peut être construit sur cette base.


Iskander Sharipov (quasilyte) travaille dans l'infrastructure dorsale de VKontakte et connaît bien NoVerify. Dans le passé, il était engagé dans le Go-compiler de l'équipe Intel. Il n'écrit pas en PHP, mais c'est son langage préféré pour l'analyse statique - il y a beaucoup de choses qui peuvent mal tourner.

Remarque. Pour comprendre le contexte, lisez l'article de Yuri Nasretdinov, l'auteur de NoVerify sur Habré, avec un contexte et une comparaison avec certains linters existants, qui sont généralement écrits en PHP. Toutes les déclarations en direction de PHP (dans l'article de Yuri et ici) sont une blague. Iskander aime PHP, tout le monde aime PHP.

Développement de produits


Dans VKontakte, il s'agit d'un développement de site Web sur KPHP. La vitesse est importante pour VKontakte: correction de bugs, ajout et développement de nouvelles fonctions de la première phase à la dernière. Mais la vitesse s'accompagne d'erreurs , surtout quand les délais sont durs - nous sommes pressés, nerveux et faisons plus d'erreurs que dans une situation calme.

Les erreurs affectent les utilisateurs . Nous ne voulons pas qu'ils souffrent, nous contrôlons donc la qualité. Mais le contrôle de la qualité ralentit le développement . Cela nous ne voulons pas non plus, donc l'effet doit être minimisé.

Pour ce faire, nous pourrions effectuer plus de révisions de code sans faute, embaucher plus de testeurset écrire plus de tests. Mais tout cela est mal automatisé: l'examen doit être fait et les tests doivent être écrits.

Les tâches principales de mon équipe sont différentes.

Collectez des métriques, analysez et réparez rapidement . Si quelque chose ne va pas, nous voulons le restaurer rapidement, comprendre ce qui ne va pas, le corriger et ajouter rapidement le code de travail à la production.

Surveillez la rigueur du pipeline afin que le code non fonctionnel ne soit pas du tout mis en production - vous n'avez pas besoin de le restaurer. Ici, les linters viennent à la rescousse - les analyseurs de code statique. Nous en parlerons.

Choisissez un linter


Choisissons un linter que nous ajoutons au pipeline. Nous adoptons une approche simple - nous formulons les exigences.

Linter devrait fonctionner rapidement . Il y a plusieurs étapes dans notre pipeline: le fonctionnement du linter ne devrait pas prendre beaucoup de temps et beaucoup de temps pour le développeur, alors qu'il attend des commentaires.

Prise en charge de "leurs" chèques . Très probablement, le linter n'a pas tout ce dont nous avons besoin - nous devrons ajouter nos propres chèques. Ils devraient trouver des problèmes typiques de notre base de code, vérifier le code du point de vue de notre projet. Tout cela ne peut pas être (ou commodément) couvert par des tests.

Prise en charge des chèques «propres». Nous pouvons écrire de nombreux tests, mais seront-ils bien pris en charge? Par exemple, si nous écrivons sur des expressions régulières, elles deviendront plus compliquées lorsque vous devrez prendre en compte le contexte, la sémantique et la syntaxe du langage. Par conséquent, les tests ne sont pas une option.

La plupart des linters que nous avons examinés sont écrits en PHP. Mais ils ne passent pas à la demande. Les linters en PHP (il n'y a pas encore de compilation AOT) fonctionnent 10 à 20 fois plus lentement que dans d'autres langues - notre plus gros fichier peut être analysé pendant des dizaines de secondes. Cela ralentit trop et trop le flux de travail - c'est une faille fatale . Que font les développeurs dans ce cas? Ils écrivent le leur.

Par conséquent, nous avons écrit notre linter PHP NoVerify sur Go. Pourquoi? Spoiler: pas seulement parce que Jura en a décidé ainsi.

Noverify


Go est un bon compromis entre vitesse de développement et productivité.
La première "preuve" de l'image avec des "infographies": bonne vitesse d'exécution, support facile. Nous perdons en vitesse de développement, mais les deux premiers points sont plus importants pour nous.


Les chiffres sont pris de la tête, ils ne sont étayés par rien.

Pour le deuxième «élément de preuve», il a plaidé plus simplement.


PHP est plus lent, Go est plus rapide, etc. 

Nous avons choisi Go pour trois raisons.

Aller comme une langue pour les utilitaires est facile à apprendre au niveau de base . Dans l'équipe de développeurs PHP, bien sûr, quelqu'un a entendu parler de Go, a regardé Docker, sait qu'il est écrit en Go, peut-être même a vu la source. Avec une compréhension de base, après une ou deux semaines d'apprentissage intensif de Go, ils pourront écrire du code dessus.

Go est assez efficace . Même un débutant ne pourra pas faire beaucoup d'erreurs, car Go a un bon réglage et beaucoup de linter. Dans Go, le code moyen est légèrement meilleur que dans d'autres langues, car il y a beaucoup moins de façons de tirer sur sa propre jambe.

Les applications Go sont faciles à entretenir.Go est un langage de programmation assez mature pour lequel presque tous les outils de développement que vous pouvez souhaiter sont disponibles.

Nous vérifierons NoVerify avec nos exigences.

  • NoVerify est plusieurs fois plus rapide que les alternatives .

  • Pour cela, vous pouvez écrire des extensions , à la fois Open Source et les vôtres. Il est important que nous puissions séparer ces chèques, et vous pouvez écrire les vôtres.
  • Facile à tester et à développer. En partie, parce que la distribution Go standard a un cadre standard avec profilage et tests. Il est principalement utilisé pour les tests unitaires. Particulièrement habile peut être utilisé pour l'intégration, comme nous le faisons - nous avons des tests d'intégration écrits via des tests Go.

Compromis d'intégration


Commençons par le problème. Lorsque vous démarrez un linter pour la première fois sur un ancien projet qui n'utilisait aucune analyse, vous le verrez très probablement.



Oh mon code! Personne ne corrigera jamais autant d'erreurs. Je veux fermer le projet, supprimer le linter et ne plus l'exécuter. Que faire pour éviter cela?

Intégrer


Exécuter en mode diff . Nous ne voulons pas exécuter tous les contrôles sur l'ensemble du projet avec un million d'erreurs à chaque étape du CI. Peut-être connaissez-vous la base de référence: dans NoVerify, cela est prêt à l'emploi, vous n'avez pas besoin d'incorporer un utilitaire distinct. Nous avons immédiatement considéré qu'un tel régime était nécessaire.

Ajoutez l'héritage (fournisseurs) aux exceptions . Il est plus facile de ne pas toucher à certaines choses, de les laisser de côté même avec un défaut, afin de ne pas le modifier vous-même et de ne pas laisser de trace dans l’histoire.

Nous commençons par un sous-ensemble de contrôles . Vous ne pouvez pas connecter tout ce qui inclut le style. Pour commencer, il trouve de vrais bugs: nous allons trouver, corriger et passer à quelque chose de nouveau.

Nous collectons les commentaires des collègues. Comment comprendre quand il est temps d'activer autre chose? Demandez à vos collègues. Dès qu'ils sont contents que les erreurs aient disparu et que presque rien ne soit trouvé, allumez autre chose - il est temps de travailler.

Configuration de Git


Le mode Diff signifie que vous avez un système de contrôle de version - Git. Si vous avez SVN, alors l'instruction n'aidera pas, allez dans Git.

Nous installons un crochet de pré-poussée avec un linter et vérifions avant de commencer le code. Nous vérifions la machine locale avec une option --no-verifypour contourner le linter . Il serait probablement plus pratique d'utiliser un hook de pré-réception et de désactiver le linter côté serveur, mais pour des raisons historiques, beaucoup de choses se produisent dans VK dans un hook de pré-push, donc NoVerify a également été intégré.

Après le push, les contrôles CI sont lancés. NoVerify a deux modes de fonctionnement: avec analyse complète et sans elle. Sur CI, vous voulez (et pouvez) exécuter--git-full-diff- les machines dans CI peuvent être chargées plus durement et vérifier même les fichiers qui n'ont pas changé. Sur les machines locales, nous pouvons exécuter une analyse moins stricte, mais plus rapide, des fichiers modifiés uniquement (5 à 15 secondes plus rapidement). 

Faux positifs




Prenons l'exemple ci-dessous: dans cette fonction, quelque chose contenant un champ est accepté, mais le type n'est décrit en aucune façon. Ce n'est pas un fait qu'il existe un champ du tout lorsqu'une fonction est appelée à partir de différents contextes. Dans une version stricte, le linter pourrait se plaindre: "On ne sait pas de quel type il s'agit, comment puis-je retourner un champ sans vérification?" Mais ce n'est pas nécessairement une erreur.

function get_foo($obj) {
    return $obj->foo;
    ^^^
}

Warning:
Property "foo" does not exist

Les faux positifs interfèrent. 
C'est la principale raison de l'abandon du linter. Les gens choisissent d'autres options qui trouvent moins d'erreurs, mais produisent moins de faux positifs.

Ils se bousculent souvent lorsque quelque chose fonctionne, mais ce n'est pas une erreur. Beaucoup ont un mécanisme pour contourner le linter - pour fonctionner avec le drapeau sans vérifier le linter. Dans notre pays, ce drapeau s'appelait no-verifyun crochet de pré-poussée. Nous l'avons souvent utilisé et le nom a été immortalisé au nom du linter.

Pickiness


Une autre propriété de linter. Par exemple, beaucoup ne comprennent pas les alias. En PHP, sizeofil s'agit d'un analogue count: il ne calcule pas la taille, mais renvoie le nombre d'éléments. Le modèle mental des développeurs C a une sizeofsignification différente. Si dans la base de code il y a sizeof, très probablement, une moyenne count. Mais c'est tatillon.

$len = sizeof($x);
    ^^^^^^

Warning:
use "count" instead of "sizeof"

Que dois-je faire avec ça?


Soyez strict et forcez à tout gouverner sans exception . Imposer des règles, exiger, observer et ne pas les laisser contourner - ça ne marche jamais. Pour qu'une telle rigidité fonctionne, l'équipe doit être composée des mêmes personnes: caractère, niveau de culture, pédanterie et perception de la qualité du code. Si ce n'est pas le cas, il y aura une émeute. Il est plus facile de constituer une équipe à partir de vos clones que de forcer à suivre toutes les règles. 

Ne pas bloquer push / engager des commentaires comme la fixation sizeofsur count. Très probablement, ce n'est pas une erreur, mais une pioche et n'affecte pas le code. Mais alors 99% des réponses seront ignorées (par l'équipe) et il y aura toujours des réponses supplémentaires dans le code sizeof.

Autorisez un certain niveau de configuration pour différentes équipes et développeurs.Vous pouvez configurer la configuration de chaque commande afin que ceux qui ne souhaitent pas passer sizeofà countne puissent pas le faire. Laissez tout le monde suivre les règles. Une bonne option, mais la cohérence s'affaissera et dans certains répertoires, le code sera légèrement pire.

Exécutez de tels contrôles une fois par mois, sur les subbotniks . Les contrôles peuvent être effectués non pas à chaque fois sur le CI ou le crochet de pré-poussée, mais dans la routine Cron une fois par mois. Exécutez et modifiez tout ce que vous trouvez après un développement actif. Mais ce travail nécessite des ressources d'automatisation et de vérification.

Ne fais rien. La désactivation des vérifications stylistiques est également une option.

Faire des compromis




Il y aura toujours un compromis entre un développeur heureux et un linter heureux. Il est facile de faire plaisir à un linter: le mode le plus strict et le manque de solutions de contournement. Peut-être qu'après cela, personne ne restera dans l'équipe, donc si le linter interfère avec le travail, c'est un problème.
Action utile avant tout.

Détails techniques de NoVerify


Chèques privés VKontakte. Noverify est écrit quelque chose comme ça. Dans GitHub, le référentiel NoVerify est divisé en deux parties: le cadre utilisé pour implémenter le linter et des contrôles séparés, vklints . Ceci est fait pour que le linter charge des vérifications tierces: vous pouvez écrire un module séparé sur Go et ils s'enregistrent dans le framework. Après avoir démarré à partir du binaire NoVerify, le framework charge tous les ensembles de contrôles enregistrés et ils fonctionnent dans leur ensemble. 



NoVerify est à la fois une bibliothèque et un binaire (linter).

Nos chèques sont appelés vklints . Ils constatent qu'ils ne voient pas PhpStorm et Open Source NoVerify - des erreurs importantes qui ne conviennent pas à un usage général.

Qu'est-ce que vklints?

Vérifier les spécificités de l'utilisation de certaines fonctions , classes et même variables globales qui ne respectent pas nos conventions. C'est quelque chose qui ne peut pas être utilisé dans des endroits spéciaux pour diverses raisons décrites dans le guide de style.

Vérifications de style supplémentaires. Ils ne correspondent pas à ce qui est accepté dans la communauté PHP, ne sont pas décrits dans la Recommandation Standard PHP ni même le contredisent, mais pour nous c'est le standard. Il est inutile de les ajouter à l'Open Source car vous ne voulez pas les suivre.

Exigences de comparaison strictes pour certains types . Par exemple, nous avons une vérification qui nécessite de comparer des chaînes avec un opérateur de comparaison ===. En particulier, cela nécessite de passer un drapeau pour une comparaison stricte des fonctions afin de comparer les chaînes.

Clés de tableau suspectes.Autre erreur intéressante: parfois, lorsque les développeurs s'engagent, ils peuvent appuyer sur des combinaisons de touches avant d'enregistrer le fichier. Ces caractères restent parfois dans une chaîne ou dans un morceau de code. Une fois, dans la clé du tableau se trouvait la lettre russe «Y». Très probablement, le développeur a appuyé sur CTRL-S dans la disposition russe, a enregistré le fichier et l'a validé. Parfois, nous trouvons de telles clés dans des tableaux, mais de nouvelles erreurs ne passeront plus.

Les règles dynamiques sont un mécanisme d'extension NoVerify plus simple décrit en PHP. Un article séparé a été écrit à ce sujet: comment ajouter des chèques à NoVerify sans écrire une seule ligne de code Go .

Comment fonctionne NoVerify


Pour analyser PHP, vous avez besoin d'un analyseur . Nous ne pouvons pas utiliser l'analyseur PHP en PHP: il est lent, à partir de Go, il ne peut être utilisé que via un wrapper en C. Par conséquent, nous utilisons l' analyseur dans Go.

Cet analyseur a plusieurs problèmes. Malheureusement, il ne peut travailler qu'avec UTF-8 et nous devons faire la distinction entre UTF-8 et non UTF-8 . En plus de UTF-8, Windows-1251 se trouve souvent dans les projets PHP russes. Nous avons également de tels fichiers. Comment les reconnaissons-nous? 

Le fichier encodings.xmlrépertorie tous les chemins d'accès aux fichiers avec UTF-8. Si nous rencontrons un fichier en dehors de ces chemins, nous diffusons à la volée en UTF-8 en streaming (sans conversion à l'avance).


Analyse et analyse


Terminé en quelques étapes. Sur le premier - nous chargeons les métadonnées de phpstorm-stubs . Ce sont des données qui ressemblent à du code PHP, mais qui ne sont jamais exécutées et décrivent les types d'entrées / sorties des fonctions standard. Les métadonnées phpStorm ont une directive de remplacement utile pour le linter ... Elle nous permet de décrire, par exemple, que nous acceptons un tableau de type T[]et retournons le type (utile pour les fonctions array_pop).


Phpstorm-stubs est chargé en premier. Nous utilisons les métadonnées comme information de type initiale - la fondation. Cette fondation est absorbée par le linter et nous commençons à analyser les sources.

Nous chargeons le maître actuel avant absorption. Nous vérifions le code en deux modes:

  • changements locaux : concernant la ligne de base, nous trouvons de nouvelles erreurs dans le code;
  • nous indiquons la gamme des révisions : la première et la dernière révision, et entre elles tout est inclusif - c'est le nouveau code, et tout ce qui «avant» est ancien.

Vient ensuite l'étape de l'analyse.



Analyse AST . Nous avons maintenant des métadonnées, tapez des informations. Nous prenons toutes les sources PHP, analysons et analysons directement au-dessus de l'AST - nous n'avons pas de représentation intermédiaire pour le moment. L'analyse d'un AST brut n'est pas très pratique, surtout si vous dépendez des bibliothèques et des types de données qu'il représente. 



Les résultats de l'analyse sont stockés dans le cache . Il est utilisé en réanalyse, ce qui est beaucoup plus rapide.

Rapports et filtrage . Ensuite, nous générons deux fois des rapports ou des avertissements : nous trouvons d'abord des avertissements pour l'ancienne version du code (avant la ligne de base), puis pour la nouvelle. Les rapports sont filtrés par comparaison (diff) - nous recherchons les avertissements apparus dans la nouvelle version du code et les transmettons à l'utilisateur. Dans certains analyseurs statiques, cela s'appelle le «mode de base».



L'analyse de code double (en mode diff) est très lente. Mais nous pouvons nous le permettre - NoVerify est toujours des dizaines de fois plus rapide que les autres éditeurs de liens PHP. Dans le même temps, il dispose d'une réserve d'accélération supplémentaire, d'au moins 30%.

Comment analysons-nous les fichiers? En PHP, vous pouvez appeler une fonction avant qu'elle ne soit définie - vous devez connaître les informations sur cette fonction avant de l'analyser. Par conséquent, nous parcourons d'abord l'intégralité du fichier dans AST, indexons, identifions les types de toutes les fonctions, enregistrons les classes, puis analysons-le. 



L'analyse est le deuxième passage dans le fichier . La plupart des interprètes et des compilateurs travaillent également avec deux passes et plus. Afin de ne pas «scanner» le fichier une seconde fois, vous devez avoir des déclarations avant utilisation, comme en C par exemple.

Inférence de type


La partie la plus intéressante est que les erreurs sont le plus souvent rencontrées ici. Elle ne correspond toujours pas à l'exactitude du système de type PHP, difficile à définir formellement.

À quoi ressemble le modèle.


Modèle sémantique (démo).

Types de types:

  • Attendu est ce que nous décrivons dans les commentaires. Nous nous attendons à certains types dans le programme, mais cela ne veut pas dire qu'ils sont vraiment utilisés en elle.
  • Réel - les vrais qui sont dans le programme. Par exemple, si nous attribuons un numéro à quelque chose, alors il est évident que intou float(s'il s'agit d'un nombre à virgule flottante) seront des types réels. 

Les types réels semblent être "plus forts" - ils sont réels, vrais. Mais parfois, nous pouvons obtenir un type uniquement par annotation.

Les annotations (dans les types attendus) peuvent être divisées en deux catégories: confiance et méfiance . Par exemple, les stubs phpstorm appartiennent à la première catégorie. Ils sont considérés comme modérés (sans erreurs) avant de les utiliser. Ceux qui ne sont pas fiables sont ceux que les autres développeurs écrivent, car ils peuvent contenir des erreurs.

Les types réels peuvent également être divisés en plusieurs parties: valeurs, assertion, prédicats et indice de type, ce qui étend les capacités de PHP 7. Mais il existe un problème que l'indice de type ne résout pas.

Attendu vs réel


Disons qu'une classe Fooa un héritier. A partir de la classe descendante, nous pouvons appeler des méthodes qui ne sont pas dans Foo, car le descendant étend le parent. Mais si nous obtenons l'héritier Foode new static()cette annotation du type de retour (de self), un problème se posera. Nous pouvons appeler cette méthode, mais l'EDI ne vous le demandera pas - vous devez le spécifier static(). Il s'agit d'une liaison statique tardive en PHP , lorsque l' Foohéritier de classe ne peut pas retourner

class Foo {
    /** @return static */
    public function newStatic() : self {
        return new static();
    }
}
// actual = Foo
// expected = static

Lorsque nous écrivons new static(), non seulement la classe peut revenir new Foo. Par exemple, si une Fooclasse est héritée de bar, alors il peut y en avoir new bar. Par conséquent, nous avons besoin d'au moins deux informations de type. Aucun d'entre eux n'est redondant - les deux sont nécessaires.

Par conséquent, le type réel ici sera self- pour l'interpréteur PHP. Mais pour l'IDE et pour que les linters fonctionnent, nous avons besoin static. Si nous appelons ce code à partir du contexte de la classe héritière, nous devons savoir que ce n'est pas la même classe de base et qu'il a plus de méthodes.

class Foo {
    /** @return static */
    public function newStatic() : self {
        return new static();
    }
}
// actual -  PHP 
// expected -   IDE/

Indice de type


La saisie statique et l'indication de type ne sont pas la même chose.
Vous avez peut-être entendu dire que vous ne pouvez vérifier que les limites des fonctions. Aux frontières, nous vérifions les entrées et les sorties, où l'entrée correspond aux arguments de la fonction. Dans la fonction, vous pouvez faire n'importe quel non-sens: attribuer une foovaleur int, bien que vous ayez décrit ce qu'elle est T. Vous pouvez vous plaindre d'avoir violé les types que vous avez déclarés, mais pour PHP il n'y a pas d'erreur

declare(strict_types=1);
    function f(T $foo) {
        $foo = 10; //  int
        return $foo;
}

Un exemple est plus difficile - on revient foo? Au début de la fonction, nous avons déterminé que fooc'était le cas T, et il n'y a aucune information sur le retour. 

declare(strict_types=1);
function f(T $foo) {
    $foo = 10; //  int
    return $foo;
}
// ? 1. f -> int
// ? 2. f -> T|int
// ? 3. f -> T

Quel type est correct? Les deux premiers, nous analyserons la différence entre eux. PhpStorm et linter produisent la deuxième option. Malgré le fait qu'il revient toujours int, le type T|intest déduit - "l'union" des types. Il s'agit d'un type auquel peuvent être affectées ces deux valeurs: d'abord, nous avions des informations sur le type T, puis nous les avons attribuées 10, donc le type de la variable foodoit être compatible avec ces deux types.

Annotations


Les commentaires et les annotations peuvent mentir.
Dans l'exemple ci-dessous, nous avons écrit que nous retournons un nombre, mais retournons une chaîne. Si le linter ne fonctionnait qu'au niveau des annotations et du type hint, alors nous considérerions qu'il revient toujours int. Mais les types réels aident simplement à s'en éloigner: ici, le type attendu est celui int-ci et le type réel est une chaîne. Linter sait que la chaîne est retournée et peut vous avertir que vous avez promis de revenir int. Cette séparation est importante pour nous.

/** @return int */
function f() { return "I lied!"; }

Héritage d'annotations. Ici, je veux dire qu'une classe qui implémente une sorte d'interface a une méthode. La méthode a de bons commentaires, une bonne documentation, des types - elle est nécessaire pour implémenter l'interface. Mais il n'y a pas de commentaires dans l'implémentation: il n'y a que @inheritdocou rien du tout.

interface IFoo {
    /** @return int */
    public function foo();
}
class Fooer implements IFoo {
    /** @inheritdoc */
    public function foo() { return "10"; }
}

Que renvoie cette méthode? Il semble que ce qui est décrit dans l'interface - soit retourné int, mais en fait une chaîne. Ce n'est pas bon: PHP est tout de même, mais la convergence est importante pour nous.

Il existe deux options pour corriger ce code. L'évidence est de revenirint . Mais vous devrez peut-être renvoyer un type différent. Que faire? Écrivez que nous renvoyons la chaîne . Dans ce cas, des informations de type explicites sont nécessaires pour l'IDE et le linter afin d'analyser correctement le code.

interface IFoo {
    /** @return int */
    public function foo();
}
class Fooer implements IFoo {
    /** @return string */
    public function foo() { return "10"; }
}

Cette information ne serait pas du tout nécessaire si les gens écrivaient des commentaires, non @inheritdoc. Il n'est pas nécessaire que PhpStorm comprenne quels types vous possédez. Mais si les types ne sont pas décrits correctement, il y aura un problème.

PhpStorm et le linter ont des ensembles de bogues disjoints lorsque nous utilisons les mêmes fichiers pour les métadonnées (types). Si nous corrigeons tout ce dont nous avons besoin dans phpstorm-stubs à partir du référentiel JetBrains, l'IDE se cassera très probablement. Si vous laissez tout par défaut, tout ne fonctionnera pas correctement

pour nous. Par conséquent, nous avons un petit fork -  VKCOM / phpstorm-stubs . Quelques correctifs ont été ajoutés pour corriger quelque chose qui ne va pas. Je ne peux pas le recommander pour PhpStorm, mais il est nécessaire que le linter fonctionne.

Open source


Noverify est un projet open source. Il est publié sur GitHub .

Brèves instructions "en cas de problème".

Si quelque chose est cassé ou ne démarre pas. La mauvaise réaction est de renvoyer et de supprimer NoVerify. La bonne réaction: émettre un ticket sur GitHub et parler de votre problème. Très probablement, il sera résolu en 1-2 jours.

Il vous manque une fonctionnalité. Mauvaise réaction: supprimez NoVerify et écrivez votre propre linter (bien qu'écrire votre propre linter soit toujours cool). La réaction correcte: pour émettre un ticket sur GitHub et, peut-être, nous ajouterons une nouvelle fonction. C'est plus compliqué avec des fonctionnalités qu'avec des erreurs - une discussion s'ensuit, et chaque personne a une vision différente de la mise en œuvre dans l'équipe. Mais à la fin, ils sont toujours en cours de mise en œuvre.

Si vous êtes intéressé par le développement du projet ou si vous voulez simplement parler d'analyse statique, rendez-vous dans notre salle de chat - noverify_linter .

PHP-, , , , PHP Russia.

, . , , . telegram- @PHPRussiaConfChannel. , .

Source: https://habr.com/ru/post/undefined/


All Articles