DressCode

DressCode je dress code pro váš PHP kód. Hlídá jeho styl, většinu nálezů rovnou opraví a kód umí i aktualizovat: přepíše ho na novější PHP, od PHP 8.0 až po PHP 8.6, i na nové verze knihoven. Pracuje nad bezztrátovým syntaktickým stromem, takže změní jen to, na co sáhne, a zbytek souboru zůstane bajt po bajtu stejný. Sám žádný styl nenosí, obléká kód podle standardu: PER Coding Style 3.1, PSR-12, Nette Coding Standard nebo Symfony. A co chcete mít jinak, napíšete klíč po klíči, tak jak to v kódu vypadá, klidně pro každou část projektu jinak.

Léta jsem používal PHP CS Fixer i PHP_CodeSniffer a bral je jako hotovou věc. Pak jsem potřeboval jedno nové pravidlo a zjistil, kolik práce dá napsat ho, když nástroj vidí jen ploché pole tokenů a strukturu kódu si musí domýšlet. DressCode vznikl proto, aby se pravidlo dalo napsat za odpoledne a aby se dalo věřit tomu, co opraví.

Konfigurace, která popisuje kód

Nástroje na styl kódu mají stovky pravidel a DressCode není výjimka: jen vestavěných je přes dvě stě. Do konfigurace je ale nejmenujete. Píšete do ní, jak váš kód vypadá, věc po věci: klíč jmenuje věc v kódu a hodnota říká, jak se píše.

use:
	- perCs
	- modernizations

braces:
	position:
		class: nextLine
spacing:
	concatenation: '$a.$b'
qualification:
	function:
		global: bare
		optimized: imported

Dá se to číst nahlas: složená závorka třídy na dalším řádku, tečka bez mezer, globální funkce holé a ty, které PHP optimalizuje, importované. Ty poslední dva řádky v PHP CS Fixeru žádné nastavení neříká. Vyjdou ze souhry dvou pravidel:

'native_function_invocation' => [
	'include' => ['@compiler_optimized'],
	'scope' => 'namespaced',
	'strict' => true,
],
'global_namespace_import' => ['import_functions' => true],

První pravidlo napíše lomítko před funkce, které optimalizuje kompilátor, a ostatním ho vezme, druhé pak každé lomítko převede na import. Nad týmž souborem dají obě konfigurace stejný kód, jen k tomu v PHP CS Fixeru vede úvaha, ne věta. PHP_CodeSniffer se Slevomatem umí lomítko před optimalizované funkce, nebo import všech globálních funkcí, ale import jen těch optimalizovaných ne.

Psát stovky klíčů přitom nemusíte, protože konfigurace stojí na dvou otázkách. Jak má kód vypadat? To je standard, jeden, a vyberete ho jménem. Co po kódu chcete kromě vzhledu? To jsou sady: modernizations, deprecations, cleanup, correctness, types a compilerOptimizations. Sada jmenuje záměr, ne výčet klíčů, a roste: když se DressCode naučí novou modernizaci, sada ji přinese bez jediného řádku v konfiguraci. Na zbytek stačí klíč, a kde nemá platit ani to, co říká standard, napíšete keep.

Celou cestu ke klíči, třeba braces.position.class, uvidíte u každého nálezu ve výpisu, takže víte, co nastavit, potlačit, nebo si nechat vysvětlit příkazem dresscode explain braces.position.class. A než klíč zapíšete natrvalo, vyzkoušíte ho na jeden běh: dresscode fix --set cleanup.is_null=forbidden ho přidá k vaší konfiguraci a jeho změny vyjdou rovnou zformátované, na jeden čistý commit. Všechny sekce a jejich klíče popisuje Struktura konfigurace.

Nejen styl, ale i aktualizace kódu

Nástroj, který kódu rozumí, se nemusí zastavit u mezer. Když zvednete verzi PHP v composer.json, sada modernizations přepíše kód na to, co nová verze přinesla, a DressCode ho v témž běhu zformátuje podle vašeho standardu:

return trim(strtolower(strip_tags($title)));
return $title |> strip_tags(...) |> strtolower(...) |> trim(...);

Stejně převede kód při aktualizaci knihoven: pro Nette nese balíček dresscode/rules-nette migrace všech dvaceti knihoven, u většiny od verze 3.0 po současnou, přejmenované třídy, konstanty, metody i parametry, a balíčky pro další ekosystémy přibývají. A když máte v projektu PHPStan, DressCode se ho ptá na typy, takže přepíše i zastaralé API podle toho, čím proměnná opravdu je. Styl i přechod na novou verzi tak obstará jeden nástroj s jednou konfigurací a jedním diffem.

Pokrytí PER Coding Style a PSR-12

Že nástroj umí standard, se napíše snadno, a tak jsem výsledek nechal posoudit konkurenci. Laravel opravený presetem perCs dostal PHP CS Fixer s vlastní sadou pro PER Coding Style a v 1 696 souborech změnil ještě 9 míst. Obráceně najde DressCode po PHP CS Fixeru 1 201 míst, kde PER Coding Style chce něco jiného, třeba jednu položku na řádek nebo čárku za víceřádkovým seznamem. U PSR-12 najde DressCode po phpcbf ještě 772 míst, mezi nimi chybějící viditelnost konstant, kterou phpcbf ohlásí, ale doplnit neumí. Čísla pro Symfony i to, co zbylo na druhé straně, rozebírá stránka Jak DressCode funguje.

Rychlost proti PHP CS Fixeru a PHP_CodeSniffer

DressCode je dělaný k tomu, aby běžel po každé úpravě souboru, a tam rozhoduje čas jednoho souboru: je to zhruba třetina až polovina času PHP CS Fixeru, u malého souboru 118 ms proti 323 ms. Rychlejší je i nad celým projektem, když dělá stejnou práci. S rozhodnutími, která odpovídají sadě PER Coding Style z PHP CS Fixeru, mu stačí 64 až 90 % času PHP CS Fixeru v jednom procesu a 46 až 64 % v paralelních procesech, nad kódem Laravelu, WordPressu, Symfony a Nette. Symfony s vlastní konfigurací PHP CS Fixeru, převedenou příkazem import, zkontroluje za 56 % jeho času (14,2 s proti 25,3 s), i když PHP CS Fixer tam navíc pouští přes sto pravidel pro phpDoc a PHPUnit, která DressCode nemá.

Preset perCs dělá víc než zmíněná sada: navíc láme dlouhé signatury, podmínky, řetězy volání a pole na řádky a opravuje velikost písmen ve jménech. Preset proti presetu proto běží nad Laravelem 72 % času PHP CS Fixeru a nad WordPressem 118 %, protože tam mají rozhodnutí navíc nejvíc práce.

Proti PHP_CodeSniffer je rozdíl vidět při opravě: dresscode fix potřebuje 36 až 54 % času, který na PSR-12 spotřebuje phpcbf. Samotné hlášení zvládne phpcs rychleji, protože dresscode check si opravy počítá v paměti i při kontrole. A přepis na novější PHP trvá zlomek toho, co Rector, nad Symfony 3.4 1,6 s proti 128,5 s, a s typy z PHPStanu je pořád rychlejší: nad Laravelem 4,4 s proti 10,5 s s nahřátou cache PHPStanu a 9,0 s proti 195 s se studenou.

Měřeno v říjnu 2026 na PHP 8.5 proti PHP CS Fixeru 3.95, PHP_CodeSniffer 4.0 a Rectoru 2.6, medián tří běhů.

Kudy dál

Používání

Reference

Rozšíření a integrace