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

Přechod na DressCode krok za krokem

Komentáře potlačující chyby fungují v kódu dál i s původními názvy pravidel a celou konfiguraci převedete jediným příkazem, který vás přehledně upozorní na vše, co nebylo možné přenést automaticky. Zde najdete osvědčený postup migrace z PHP CS Fixeru, PHP_CodeSnifferu i Laravel Pintu – včetně otevřeného přehledu toho, co bude fungovat jinak.

Instalaci popisuje stránka Začínáme s DressCode a kompletní výčet parametrů pro příkazy migrate, init a fix najdete v referenci příkazové řádky.

Proč to nebolí

Víme, jak to v praxi chodí: v projektu máte konfiguraci laděnou dlouhé roky, ve zdrojácích stovky komentářů phpcs:ignore, možná pár vlastních sniffů a k tomu zaběhnuté CI, které to celé hlídá. Nikdo nemění nástroj jen proto, že ten nový vypadá moderněji. Změna dává smysl teprve ve chvíli, kdy přechod nebolí – a přesně na to byl DressCode od začátku navržen.

Zásadní výhoda spočívá v tom, že DressCode u každého svého rozhodnutí přesně ví, která pravidla PHP CS Fixeru, PHP_CodeSnifferu a Slevomatu pokrývá. Když spustíte dresscode catalogue, uvidíte původní pravidla vypsaná u každého rozhodnutí v závorce covers. Z toho plyne vše podstatné: stávající komentáře v kódu fungují beze změny a starou konfiguraci zvládne nástroj přeložit strojově. Do nové konfigurace a na příkazovou řádku už ale zapisujete čisté cesty rozhodnutí DressCode, například imports.unused.

Celý proces probíhá ve třech bezpečných krocích a každý z nich můžete kdykoliv vrátit zpět. Druhý a třetí krok navíc plně automatizují dva podpříkazy z rodiny dresscode migrate.

1. Kód nechte, jak je

Komentáře // phpcs:ignore, phpcs:disable, phpcs:enable, phpcs:ignoreFile i anotace @phpcsSuppress fungují i nadále. DressCode je při průchodu přečte, původní název pravidla si sám přeloží na odpovídající rozhodnutí a potlačení normálně uplatní. Do zdrojového kódu tedy zatím nemusíte vůbec sahat a první kontrolu můžete spustit okamžitě:

dresscode check src tests --use perCs

Je tu však jeden důležitý rozdíl v chování, o kterém musíte vědět: phpcs:ignore na samostatném řádku potlačoval v PHP_CodeSnifferu pouze bezprostředně následující řádek. DressCode jej naproti tomu interpretuje stejně jako vlastní direktivu dresscode:ignore – tedy tak, že na samostatném řádku platí pro celý následující příkaz, i když je roztažený přes více řádků. Potlačení tak může v některých případech pokrýt o něco větší kus kódu než dříve.

Konfigurační soubor v této fázi ještě nemáte, a protože DressCode bez zadání pravidel nic nekontroluje, určuje standard parametr --use. Hodnota perCs znamená PER Coding Style 3.1. Pokud jste dosud používali @PER-CS nebo PSR12, uvidíte zhruba to, na co jste zvyklí. Pokud jste měli pravidla detailně přizpůsobená nad rámec standardu, narazíte na odchylky, které vyřeší hned následující krok.

2. Přeložte konfiguraci

Příkaz migrate config automaticky vyhledá konfiguraci vašeho projektu (ať už patří PHP_CodeSnifferu, PHP CS Fixeru, nebo Laravel Pintu) a její ekvivalent pro DressCode zapíše včetně kontrolovaných cest přímo do dresscode.neon. Pokud přecházíte z prostředí bez konfigurace, nebo žádnou nemáte, nechte si ji raději změřit přímo z existujícího kódu pomocí příkazu dresscode init:

dresscode migrate config
dresscode migrate config conf/phpcs.xml --output dresscode.php

Nástroj hledá konfigurační soubory na obvyklých místech a vybere ten, který projekt reálně používá. Postupuje systematicky: nejprve prověří skripty v composer.json, zda některý z nich nespouští formátovač s konkrétním souborem (např. phpcs --standard=conf/phpcs.xml, a to i vnořeně přes aliasy typu @lint). Následně zkontroluje konfiguraci nástroje, jehož balíček projekt vyžaduje v závislostech, a nakonec hledá soubory ležící přímo v kořeni projektu (lokální .php-cs-fixer.php před .php-cs-fixer.dist.php). Pokud v kořeni objeví více kandidátů, v interaktivním terminálu se vás zeptá, který z nich platí; mimo terminál zvolí první a ostatní vypíše. Cestu k jinému souboru můžete samozřejmě předat přímo jako argument. Kam se má výsledek uložit, určí přepínač --output; formát výstupu se řídí příponou .neon nebo .php a již existující soubor migrate config nikdy nepřepíše. Před samotným zápisem si vygenerovaný soubor cvičně načte a ověří, že z něj vzejdou přeložená rozhodnutí; s přepínačem --dry-run výsledek pouze vypíše do konzole. Soubor patří do kořene projektu, protože uvedené cesty jsou relativní právě k tomuto kořeni.

Zatímco phpcs.xml je běžné XML a pint.json standardní JSON (oba formáty DressCode přečte bez jakýchkoliv závislostí), se souborem .php-cs-fixer.dist.php je to jiné: jde o spustitelný PHP skript, který vrací instanci cizí knihovny. Pokud na něj migrate config narazí sám, nejprve se v terminálu zeptá na svolení ke spuštění; bez interaktivního terminálu jej z bezpečnostních důvodů nespustí vůbec a pouze vypíše doporučený příkaz. Skript spouští v izolovaném procesu s autoloaderem projektu, takže vyžaduje, aby byl PHP CS Fixer v projektu stále nainstalovaný (samotný DressCode přitom může běžet odkudkoliv, viz podrobnosti na stránce PHP CS Fixer). Z toho důvodu překládejte konfiguraci dříve, než starý nástroj z projektu odinstalujete.

Z konfigurace phpcs.xml, která kontroluje složky src a tests, vychází z PSR12, omezuje délku řádku na 100 znaků, hlídá nepoužité importy a vyžaduje dokumentaci funkcí, vznikne tento čistý dresscode.neon:

use: psr12

paths: [src, tests]

file:
	lineLength: 100
	lineLengthExcept: [imports]
	longLines: forbidden

imports:
	unused: forbidden             # `SlevomatCodingStandard.Namespaces.UnusedUses` without `searchAnnotations` removes an import only a doc comment uses; DressCode keeps it.

Příkaz vypíše, jakou konfiguraci našel a kam uložil výsledek, a pod tím zobrazí souhrn včetně věcí, které se nepodařilo přenést:

Found `phpcs.xml` of PHP_CodeSniffer.
Written `dresscode.neon`.

Read 4 rules; set 4 decisions and 1 preset, the rules translated; `dresscode init` measures the code instead.
  `SlevomatCodingStandard.Namespaces.UnusedUses` without `searchAnnotations` removes an import only a doc comment uses; DressCode keeps it.
  No DressCode rule covers `Squiz.Commenting.FunctionComment`.

5 phpcs suppression comments: `dresscode migrate suppressions` rewrites them.

Tyto řádky mají stejnou cenu jako vygenerovaná konfigurace: přesně pojmenovávají místa, kde se musíte rozhodnout sami. Zde vás například informují, že DressCode zachová import využívaný pouze v phpDoc komentáři, zatímco původní sniff bez volby searchAnnotations by jej smazal. Varování k pravidlu, které se podařilo přeložit jen částečně, se navíc uloží přímo jako komentář k danému rozhodnutí v souboru, aby nezmizelo se zavřením okna terminálu. Pokud příkaz vypíše jakékoliv varování, skončí s exit kódem 1, i když soubor v pořádku zapsal. Pravidlo bez přímého protějšku buď vůbec nepotřebujete, nebo si na něj snadno napíšete vlastní kontrolu. Obecné sady jako @PSR12 nebo PSR12 se překládají na standardy; u sad bez jednoznačného protějšku (např. @PhpCsFixer) na to příkaz upozorní a doporučí začít od standardu perCs či psr12. Výpis zároveň připomene druhou cestu: dresscode init pravidla nepřekládá, ale změří reálný styl vašeho kódu. S přepínačem --format json získáte strukturovaný dokument obsahující verzi, kořenový adresář, přehled varování a nepřeložená pravidla – v tomto režimu se nástroj na nic neptá, stejně jako mimo terminál.

Jedno původní pravidlo se v DressCode často rozpadne do několika přesných rozhodnutí: například Generic.Files.LineLength s volbou absoluteLineLimit vygeneruje rozhodnutí file.longLines, file.lineLength a file.lineLengthExcept. Ne každá specifická volba má v DressCode svůj protějšek, což výpis opět transparentně přizná. Pravidlo, které bylo v původním nástroji výslovně vypnuté, získá hodnotu keep. Pokud však stejné rozhodnutí pokrývá i jiné pravidlo daného nástroje, nechá jej příkaz netknuté a vypíše varování, protože nemůže vědět, které z nich má mít přednost. Výsledný soubor si projděte – bývá příjemně krátký.

3. Přepište komentáře

Komentáře v kódu sice fungují i se starými názvy, ale nativní cesty rozhodnutí jsou kratší, jednotné a mnohem čitelnější. Kolik takových komentářů v projektu máte, vyčíslil už předchozí příkaz migrate config. Samotný přepis obstará jediný příkaz:

dresscode migrate suppressions src tests

Zápis phpcs:ignore SlevomatCodingStandard.Namespaces.UnusedUses se promění na dresscode:ignore imports.unused, z phpcs:disable a phpcs:enable vzniknou dresscode:disable a dresscode:enable a ze souborového phpcs:ignoreFile se stane dresscode:ignoreFile. Anotace @phpcsSuppress zůstane zachována a změní se v ní pouze název pravidla. Pokud příkaz narazí na phpcs:ignore na samostatném řádku, připomene rozdíl v rozsahu platnosti na řádku Widened a vypíše konkrétní místa, která stojí za kontrolu. Názvy, které žádné rozhodnutí nepokrývá, ponechá beze změny a vypíše je na řádku Unknown:

Migrated 5 suppressions in 1 file.
Unknown    `Acme.Custom.Sniff`, kept as written, as no decision answers to it: src/Legacy.php:12
Widened    src/Legacy.php:10: a `dresscode:ignore` on a line of its own covers the whole statement below it, not just the next line

Získáte tak jasný přehled neplatných komentářů, které reálně nic nepotlačují, protože DressCode pravidlo s takovým jménem nezná. Jelikož tyto komentáře nebylo možné přenést, skončí příkaz s exit kódem 2. Pokud se objeví pouze rozšířená potlačení z řádku Widened, vrátí příkaz exit kód 1, protože tato místa pouze čekají na vaši zběžnou revizi.

Přepisují se výhradně skutečné direktivy – tedy takové, za kterými bezprostředně končí komentář nebo řádek. Pouze takto totiž DressCode potlačení čte; věta v komentáři, která phpcs:ignore pouze zmiňuje v textu, zůstane nedotčena. Soubor, který nelze naparsovat nebo který se během práce změnil, příkaz přeskočí, uvede jej na řádku Skipped a skončí s kódem 2. S volbou --dry-run ukáže všechny plánované změny v podobě diffu a nezapíše nic. S přepínačem --format json vydá kompletní data pro další strojové zpracování.

První oprava

Jakmile máte konfiguraci vyladěnou, spusťte dresscode fix a výsledek uložte do samostatného commitu bez jakýchkoliv jiných úprav. I u pravidel, která dělají „totéž“, se může formátování v detailech lišit o mezeru oproti starému nástroji. Nemá smysl procházet tisíce řádků ručně – zásadní je mít jistotu, že daný commit neobsahuje žádnou věcnou změnu logiky. U rozsáhlejších projektů, kde by byl jeden obří commit nepřehledný, postupujte po jednotlivých sadách či sekcích: spusťte dresscode fix --only cleanup nebo dresscode fix --only blankLines a každý krok commitněte zvlášť. Závěrečný plný fix pak doladí zbytek (více v kapitole Uklidit starý kód po krocích). Problémy, které fix neumí vyřešit sám, zůstanou ve výpisu. Pokud je jich více, než kolik stíháte vyřešit hned, příkaz dresscode baseline je uloží do baseline a od té chvíle se budou hlásit už jen nově vzniklé chyby.

Co bude jinak

Návod, který slibuje stoprocentně bezbolestný přechod bez jakýchkoliv odlišností, ztratí vaši důvěru při prvním zádrhelu. Pojďme si proto otevřeně říct, v čem se věci liší:

  • Rozhodnutí namísto stovek pravidel. V konfiguraci nevyjmenováváte konkrétní pravidla ani jejich interní volby, ale přímo popisujete požadovaný stav: blankLines.aroundMethods: 1 nebo imports.unused: forbidden. Která konkrétní pravidla se o to postarají, necháváte na DressCode (viz Rozhodnutí místo pravidel). Kompletní přehled všech možností nabízí stránka Pravidla.
  • Priority neexistují. Pokud jste byli zvyklí spoléhat na ručně laděné pořadí fixerů, můžete u některých specifických souborů získat trochu jiný výsledný kód. Pravidla v DressCode běží opakovaně, dokud se kód zcela neustálí; důvody vysvětluje kapitola Bez priorit: pravidla běží do ustálení.
  • Některá pravidla nemají protějšek. Příkazy migrate config i migrate suppressions vás na ně přímo upozorní. Jde především o detailní sniffy kontrolující obsah dokumentačních komentářů nebo pravidla, která v původních nástrojích řešila vzájemné překryvy.
  • Riziková pravidla zde nemusí být riziková. To, co PHP CS Fixer zapínal pouze na výslovné vyžádání (protože nad pouhými tokeny nedokázal odlišit bezpečný případ od nebezpečného), řeší DressCode na úrovni syntaktického stromu a bezpečné výskyty opraví automaticky. Zásah, který by mohl změnit chování, se nahlásí jako riziková oprava (risky fix) a provede se teprve po schválení v klíči fixRisky nebo s parametrem --fix-risky. A rozhodnutí, které mění chování z podstaty věci (expressions.comparison.loose: forbidden nahrazující == za ===), zůstává plně ve vaší režii.
  • Návratové kódy mají jasnou stupnici: 0 znamená čisto, 1 nálezy k řešení, 2 selhání na některém souboru a 3 chybu v konfiguraci či parametrech. Jednotnou škálu popisuje Příkazová řádka. PHP_CodeSniffer i PHP CS Fixer používají vlastní škály, takže případné vyhodnocovací skripty v CI budou vyžadovat drobnou úpravu.
  • Jeden nástroj místo kombinace dvou. Mnoho projektů dříve kombinovalo CodeSniffer na kontrolu a Fixer na opravy, což znamenalo dvě konfigurace a dva kroky v CI. DressCode obojí sjednocuje pod jednu střechu.
  • Rozhodnutí si vyzkoušíte bez zásahu do konfigurace. Příkaz dresscode check --set controlFlow.elseAfterReturn=forbidden --only controlFlow.elseAfterReturn --diff ukáže dopad konkrétního pravidla v diffu, a dresscode fix --set … jej dočasně přidá ke zbytku konfigurace, takže změny vyjdou rovnou zformátované podle vašeho standardu (viz Jedno rozhodnutí na jeden běh).
  • Popisujete záměr, ne výčet pravidel. Konfigurace stojí na dvou pilířích: standard určí vzhled a sady definují, co dalšího od kódu očekáváte. Sad je přesně šest a tvoří uzavřený výčet, takže z položky cleanup v klíči use se nikdy nestane dvacet nepřehledných řádků, i když katalog časem přinese desítky nových kontrol.
  • Modernizaci kódu obstará stejný nástroj. DressCode umí kód nejen formátovat, ale i automaticky přepsat na novější PHP či nová API vašich knihoven – a to v tomtéž běhu a podle stejného standardu. Na upgrade kódu tak nepotřebujete další externí nástroj s vlastní konfigurací (viz Přechod na novější PHP a Upgrade kódu).

Podrobné návody pro jednotlivé nástroje: PHP CS Fixer, PHP_CodeSniffer a Slevomat, Nette Coding Standard, Laravel Pint.

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