PHP 8.6 arrives on November 19. DressCode already rewrites code for it. 16 days Upgrading to a newer PHP →

A Configuration Measured from Your Code

You do not have to write your first configuration: dresscode init in the root of the project measures the code you already have and tailors a dresscode.neon to fit it. It does not guess. It measures the value of each decision with the rule that will later check it, counting the places the rule reports, so what was measured and what is checked cannot drift apart.

dresscode init
DRESS|CODE 1.3.0  looking at /var/www/shop to write its `dresscode.neon`

Project    13 PHP files in git, acme/shop
Excluded   fixtures        test data
           src/Generated   generated
           not measured: 1 file git does not track, which the first fix takes too
PHP        8.2 and newer, from `composer.json`
Standard   perCs (PER Coding Style), the nearest to your code by the files a fix changes, 13 under psr12; `--use` names another
Measured   your code departs from it in 3 decisions over 13 files; perCs as it is, with no decision below `use`, would rewrite 13 of them
As written indentation.unit: tab   your code, 92% of 13 files
           blankLines.beforeDeclaration: 2   your code, all 13 places
           braces.emptyBody.function: expanded   your code, all 26 places
Checked    all 13 files: a fix changes 1 file, 1 of them for the indentation, the line endings or the long lines the rest of the code has
Your call  `dresscode init --use nette` measures against nette instead, where there is no `dresscode.neon` yet

Written    `dresscode.neon`
Next       `dresscode fix`        rewrites 1 file in place (`dresscode check --diff` shows the changes first); until then `check` reports them

First, init finds the files of the project: what Git tracks or, without Git, the autoload paths from composer.json together with the directories src, tests, test, app, lib, bin, cron and www* that actually exist in the root. It leaves out test data (the directories fixtures, Fixtures and expected), files that their header or linguist-generated in .gitattributes marks as generated by a tool, tests in the PHPT format, what Git ignores, and files that do not parse, because nobody writes any of these by hand. It writes every such file or directory into the excludePaths key together with the reason, so that every later check leaves it out too; the Excluded line lists them. A file Git does not track yet but does not ignore either is not measured; the not measured line counts it all the same, because the first fix will process it too.

Then it chooses the standard: it checks the code against each standard and takes the one under which a fix would change the fewest files, and the Standard line says so. It counts files, not decisions, because a difference across the whole project weighs more than a difference in a single place. When two standards are close, within a tenth, the one named in the configuration of the project's formatter wins. The framework the project is built on does not decide: an application built on Nette or Symfony need not follow its style. When the formatter names none, init takes perCs if it is among the close ones, and in a terminal it asks whether you would prefer another of them; if you pick one, it measures against that one. Outside a terminal, instead of asking, it prints a Your call line with the command that measures against the other one. The psr12 standard gives way to perCs, its successor, unless the formatter names it or a fix under perCs would change more than 1.5 times as many files: PSR-12 says nothing about the newer constructs of PHP, so code written to PER Coding Style 3.1 departs from it in fewer decisions. A project formatted by Laravel Pint gets the standard of its preset, and a standard given with the --use option is taken as it is. Sets given with further --use options are written after the standard, so dresscode init --use nette --use modernizations writes both names into the use key.

Then it measures the decisions in which the code departs from the standard, each one separately and with each of its values. It measures the indentation, the line length and the line endings first, because everything else depends on them. A project of up to a thousand files and 8 MB is measured in full. A larger one is measured on a sample split evenly among its directories, so that one large directory does not outweigh the others; the Sample line says how many files each directory contributed. A value that at least 70% of the places agree on is written together with what it rests on (your code, 92% of 13 files). Where the code writes the same thing in several ways and none of them prevails, init writes keep, which means “do not check”, with a not checked: comment and what it found in the code; the Unchecked line says how many such decisions there are.

A directory whose files write the indentation or one of the file.* decisions differently from the rest of the project (in at least five files and in nine tenths of them) gets a Differs line with the override that would let it keep its own style. Only you can write it, though: init proposes one style for the whole project, and an override is your decision.

Differs    tests: indentation.unit 4 spaces in all 6 files; an override for `tests` would keep it, none is written

Finally, it runs the whole configuration over all files. The first fix after init should not rewrite half of the project, so there is a budget: the fix may change 1% of the files, but never fewer than 2 or more than 20; the --budget option sets a different number. When the fixes together would change more files, init leaves some decisions unchecked until the rest fits the budget, and asks you about them, showing a place in the code that each one concerns. The indentation, the line length and the line endings are never left unchecked, because the other decisions depend on them; fix corrects the files that write them differently from the rest of the project regardless of the budget, and the Checked line counts them separately. Your answers do not count against the budget either. The findings that no rule fixes belong in the baseline; the same line says how many there are.

Standard   nette (the Nette Coding Standard), as given
Measured   your code departs from it in 4 decisions over 13 files; nette as it is, with no decision below `use`, would rewrite 13 of them
As written file.strictTypes.position: nextLine   your code, all 13 files
Checked    all 13 files: a fix changes 1 file, 1 of them for the indentation, the line endings or the long lines the rest of the code has
           1 more decision is left as your code has it, as the fixes together would change more than 2 files, the indentation, the line endings, the long lines and your answers aside (`--budget` raises the limit)

Check `literals.quotes: single`? A fix rewrites 3 files, more than the budget allows.
           e.g. src/Cart.php:18  A plain string must be written with single quotes.
  [1] don't check it (recommended)
  [2] single everywhere, a fix rewrites 3 files
Your choice [1/2]

You answer with the number in the square brackets. The recommended answer always comes first, as number 1, and pressing Enter accepts it; it leaves your code as it is, so if you are not sure, you cannot break anything. The answers that change the code show how many files the fix would rewrite. When your answers change the configuration, init checks it again, so that the Checked line also holds for what you chose. If the budget then leaves another decision unchecked, it asks about that one as well and says that your answers caused it. The questions of one round are numbered, (2/3), so you know how many are left.

What does init ask about? About the decisions the budget left unchecked, and about the standard when two are close, as described above. It also asks about a value the configuration of the project's formatter contradicts, and about names that do not use the case the standard requires and share a prefix or a suffix, such as classes ending with an underscore; a pattern in naming.except can let them pass. It asks about at most five decisions, the costliest first.

init does not ask whether to take the standard as it is; the Measured line only shows what that would cost: here nette would rewrite all 13 files, mostly because of a single decision, as your code always puts declare(strict_types=1) in a different place than nette does. A difference like that is often a trace of a standard that has changed since. If you want to follow it, delete the decision file.strictTypes.position from dresscode.neon and run fix; otherwise the value init measured from your code stays.

Without a terminal, with the --yes option or with --format json, init asks nothing and takes the recommended answers, so it writes the same file as if you had answered every question by pressing Enter. It then prints each question on a Your call line, in the form of a dresscode.neon line or a command that gives a different answer:

Your call  `literals.quotes: single` in `dresscode.neon` checks it too; its fix changes 3 files

You can also give an answer in advance: dresscode init --set literals.quotes=single writes the value regardless of what the code says, and the budget never leaves it unchecked. The path and the value are checked against the catalogue before measuring starts, so you learn about a typo before the measuring, not after it.

With the --dry-run option, init prints the configuration below the report and writes nothing. --jobs limits how many processors the measuring uses, and --jobs 1 measures in a single process. With --format json, it prints a single document for a tool or an AI agent instead of the text: the version of the format in version, the root of the project in root, the scope in scope, the sample in sample, the standard in standard with the number of files a fix would change under each one, the values in values with their comments and origins, the directories of the Differs line as regions, the check over all files in verification, the Your call lines as instructions, the files a rule failed in as failed, the configuration in configuration, and the file it was written to in written; when a configuration already exists, also what has moved since it was written, in shifts.

The written file shows what every value rests on, right next to it:

# made to measure by `dresscode init`; run it again to see what has moved since, it writes nothing over this file
use: perCs   # PER Coding Style, of the standards the one a fix changes the fewest files of your code under

paths: [src, tests]
excludePaths:
	- fixtures        # test data
	- src/Generated   # generated

# the namespaces of the scope declare no function and no constant, so an unqualified name in a namespace
# is resolved for certain; one declared later is reported until it is listed
nameResolution: certain

indentation:
	unit: tab                # your code, 92% of 13 files

braces:
	emptyBody:
		function: expanded   # your code, all 26 places

blankLines:
	beforeDeclaration: 2     # your code, all 13 places

Besides the decisions, init also writes what the namespaces declare. Here what matters is not the majority but completeness, so it goes through all files, finds the functions and constants declared in namespaces, writes their lists into the namespaces key and adds nameResolution: certain. The page Functions and Constants in Namespaces describes what these keys mean. If it finds phpstan/phpstan among the installed packages, it also writes typeAnalysis: phpstan with a comment on what the types bring. init never writes the fixRisky key: permission for fixes that may change the behavior of the code cannot be measured from the code.

If the project has PHP_CodeSniffer, PHP CS Fixer or Laravel Pint, init reads its configuration but never runs it without your consent. It picks the configuration the same way as migrate config, choosing the one the project actually runs, and in a terminal it asks when it cannot tell. From that configuration it takes the paths the formatter checks, the files it leaves out, and the rules turned off in only part of the project, for which it writes an override. It compares the rules of the formatter with what the code actually follows, and where they contradict each other, it asks which value to write. The configuration of PHP CS Fixer, however, is PHP code: init reads the paths of its Finder from the code and lists under the Formatter line those it could not read, but the rules can only be learned by running the configuration, so in a terminal init first asks whether it may. To use a different configuration from the one it picked, name it with the --formatter option; naming it also gives your consent to read its rules, even when it is PHP. At the end it says where dresscode check can replace the formatter, whether it compared the rules of the formatter with the code or did not read them at all, and that dresscode migrate config translates them instead of measuring the code; either way, the rules of the formatter are not carried over into the written file. It also says how many phpcs suppression comments dresscode migrate suppressions would rewrite.

At most two commands remain, and init prints them itself: dresscode fix fixes the files that depart from the written configuration, and dresscode baseline records the places that no rule fixes, so that check passes.

Before it writes the file, init loads it as a configuration and checks that it yields the same values it measured. When a rule fails in a file, it leaves that file out of the measuring, names it in the header of the written file and ends with exit code 2, because the configuration then rests only on the rest of the code. It never overwrites an existing configuration, so when one exists, it asks nothing and refuses --set; if it cannot read the file, it stops and gives the reason before measuring anything. Instead, it measures the project again against the standard that file names, over the files the configuration checks (it leaves out the files to which an override gives decisions of their own, and says so). It lists every decision it would write differently today, with the number of files a fix under the value in the file would rewrite, and every decision the file sets differently from the standard although the code follows the standard. This is useful after you update DressCode or after you have worked on the project for a while:

Compared   the code with the standard and the decisions of `dresscode.neon`, over the files it checks
Moved      nothing: `dresscode.neon` says what init measures

`dresscode.neon` exists, so nothing is written; `dresscode check --set path=value` shows what a value would change.

Show on GitHub · Report a problem with this page on GitHub · Nov 2, 2026