PHP 8.6 vychází 19. listopadu. DressCode pro něj kód přepisuje už teď. 14 dní Přechod na novější PHP →

Rozšiřování DressCode

Vlastní pravidlo pro váš tým, preset pro všechny vaše projekty, plugin, který je rozdá jako balíček, analýza pro víc pravidel, nebo data, se kterými si uživatelé vaší knihovny přepíšou kód na její novou verzi: kdy sáhnout po kterém z pěti rozšíření DressCode a na které jeho třídy se dá spolehnout jako na veřejné API.

Pět míst, kam se dá sáhnout

Pravidlo je odpověď na „chci hlídat ještě tohle“. Ohlásí rozhodnutí, která vynucuje, a buď jako NodeRule řekne, které uzly ho zajímají, položí otázku a případně opraví, nebo jako GapRule vysloví nárok na bílé znaky mezi tokeny. Uživatel pak píše jeho rozhodnutí stejně jako rozhodnutí jádra: pravidla projektu v sekci project, pravidla pluginu v sekci pojmenované po pluginu. Napíšete ho za odpoledne: Jak napsat vlastní pravidlo.

Preset je odpověď na „chci tenhle styl na všech projektech“. Soubor NEON ve tvaru konfigurace, který nese rozhodnutí, může vycházet z jiného presetu a dá se použít pro celý projekt i jen pro jeho část. Viz Vlastní preset a plugin.

Plugin je odpověď na „chci to rozdávat jako balíček“. Třída s rozhraním DressCode\Plugin, jejíž jediná metoda getManifest() vrátí PluginManifest: pravidla balíčku, sekci jejich rozhodnutí, rozhodnutí sdílená víc pravidly, presety se jmény, pluginy, na kterých staví, analýzy, vyloučené cesty, filtr souborů a adresu stránek pravidel. Projekt ho uvede v klíči use vedle presetů, a to třídou nebo jménem balíčku, který ho ohlásí v extra.dresscode.plugin svého composer.json; plugin, který je jen nainstalovaný, se nenačte, protože přináší kód, který běží při každé kontrole. Jak má kód vypadat, plugin nerozhoduje: rozhodnutí napíše projekt nebo preset. Viz Vlastní preset a plugin.

Analýza je odpověď na „tuhle informaci o souboru potřebuje víc pravidel“. Obyčejná třída postavená nad stromem, kterou si pravidla vyžádají; jádro ji vytvoří jednou a po každé změně stromu zahodí, jen analýza s rozhraním PassAnalysis vydrží celý průchod. Vestavěné jsou NameResolver a Scope, PhpDoc, PhpSymbols s PhpSignatures (co deklaruje samo PHP) a Types (typy kódu z PHPStanu projektu). Viz Pravidlo do detailu.

Data pro upgrade jsou odpověď na „nová verze mé knihovny přejmenovala API a uživatelé to mají opravit“. Nejsou to pravidla, ale soubory NEON v adresáři, který balíček ohlásí v extra.dresscode.upgrading-dir, a plní mapy jádra jako upgrading.api.replacedClasses nebo mapy pravidel pluginů. Viz Mapy náhrad.

Co rozšířit nejde, je parser. Je to samostatná knihovna PhpSyntax, jeho gramatikou je PHP a nic jiného a strom, který z něj vzejde, je pro všechna pravidla stejný. Právě proto se dají pravidla skládat, aniž by o sobě musela navzájem vědět. A nejde ani přidat vlastní formát výstupu: výstup je samostatná smlouva, a kdo chce výsledky zpracovat jinde, přečte JSON z dresscode check --format json.

Co je veřejné API

Na tyhle třídy se plugin může spolehnout mezi minoritními verzemi:

  • psaní pravidla: Rule s potomky NodeRule a GapRule, RuleInfo, RuleContext, Claim, Space, Line, Gap, Style s podobou importů ImportStyle, Violation a výčty Stage, Severity, Tristate a Risk;
  • rozhodnutí: Decision, Domain s obory v Domains\ (Words, Shapes, Count, Flag, Names, Text, GrammarEntry, Map), hodnoty Values a Value s vrstvou, která hodnotu určila (Config\Layer, Config\LayerKind), a katalog Config\Catalogue;
  • konfigurace: Config, Profile, Override, Plugin a PluginManifest; presety jsou soubory NEON a jejich jména;
  • pomocníci pravidel: GlobalCalls (kterou globální funkci volání volá), CodeWriter (kód zapsaný v podobě, jakou soubor má), QualifiedNames (dvě poloviny plně kvalifikovaného jména) a gramatika map v Upgrading\ (MemberMap, MemberMapGrammar, MemberPattern, MemberMapMatch, ArgumentPattern, ArgumentPatternItem, ArgumentBindings, FunctionPattern); vestavěná pravidla v Rules\ jen jménem a jmenným prostorem třídy, aby je šlo jmenovat v konfiguraci, jejich metody veřejné nejsou;
  • analýzy a testování: všechno v Analyses\ kromě Registry, PhpStan, PhpSymbolsData a PhpSignaturesData, dále Testing\RuleTester a Testing\UpgradingTester i s jejich výjimkou Testing\TestFailure a výsledek souboru FileResult, který vrací UpgradingTester::runSample();
  • příkazová řádka: Console\Application a Console\UsageException pro program, který chce běh vložit do sebe;
  • výjimky: ConfigurationException, RuleException, ConvergenceException;
  • z knihovny PhpSyntax všechno, co není označené @internal: Parser, Lexer, Printer, Node, Token, Trivia, uzly, analýzy, Style, Indentation, výčty a ParseException.

Co je označené @internal, se může změnit kdykoli: jádro, načítání a řešení konfigurace, výstupní formáty a pomocníci, které si vestavěná pravidla sdílejí jen mezi sebou. Program, který chce DressCode spustit, ho proto spouští z příkazové řádky. Oba seznamy hlídá test, takže kvůli třídě, která není ani v jednom, testy selžou, místo aby se nedopatřením stala veřejným API. A protože s novou syntaxí PHP může v minoritní verzi přibýt nový uzel stromu, potřebuje každý match přes třídy uzlů větev default.

Některé veřejné třídy vytváří jen jádro: FileResult, ImportStyle, LineSplits nebo MemberMapMatch pravidlo čte, ale nevytváří, a jejich konstruktor je proto @internal. Co se smí mezi verzemi změnit a co ne, shrnuje stránka Zpětná kompatibilita DressCode.

Pojmenování rozhodnutí

Co uživatel píše a čte, je cesta rozhodnutí, a tak na jejím jménu záleží nejvíc. Cesta jmenuje věc v kódu, ne krok, který dělá oprava: acme.exceptionMessagePeriod: required, ne acme.addPeriod: true. Hodnota pak říká, jak se ta věc píše, a vestavěný katalog na to má ustálená slova: forbidden a required pro to, co v kódu být nesmí, nebo musí (v sekci upgrading i pro konstrukci novějšího PHP a náhradu zavrženého API), sameLine a nextLine pro polohu tokenu, ukázku kódu v uvozovkách pro tvar, počet pro prázdné řádky. Kde má věc víc míst, dostane každé svůj klíč (braces.position.class, braces.position.function), a parametr, který jen upřesňuje, nese jméno toho, co upřesňuje (mistakes.debugOutputFunctions). Cesty se píšou v camelCase.

Třída pravidla nese podle konvence příponu Rule a jméno stavu, který vynucuje, takže ExceptionMessagePeriodRule vynucuje acme.exceptionMessagePeriod. Z tohoto jména bez přípony, s malým prvním písmenem, skládá ruleUrl adresu stránky pravidla. Jméno presetu má tvar vendor/name a sekce pluginu jméno pluginu. Je to konvence vestavěného katalogu a plugin, který se jí drží, do něj zapadne.

Zobrazit na GitHubu · Nahlásit problém se stránkou na GitHubu · 2. 11. 2026