Nette Coding Standard

Do you want your PHP code to follow the Nette coding standard without keeping an eye on tabs, braces and blank lines yourself? DressCode checks every file for you and fixes what it finds with a single command.

DressCode is the next generation of the original nette/coding-standard package. It has the Nette coding standard built in under the name nette. It changes only what breaks the standard and leaves the rest of the file exactly as it was, so the diff after a fix contains the fixes and nothing else.

Installation

Install DressCode globally using Composer:

composer global require dresscode/dresscode

and make sure your global vendor binaries directory is in your $PATH environment variable.

DressCode itself runs on PHP 8.4 to 8.6. That is the PHP of the tool, not the PHP your code is written for: your project can target any version from PHP 8.0 up. DressCode reads it from the php item in the require section of your project's composer.json and never writes syntax that version does not know.

Configuration

DressCode has no style of its own, so first you tell it which standard your project follows. Create a dresscode.neon file in the project root:

use:
	- nette

paths:
	- app
	- tests

The use key picks the standard, paths lists the directories to check. Commit the file, so that everyone on the team, and your CI too, checks the code the same way.

Usage

Let's try it on a class written in a hurry, app/Model/CartService.php, indented with spaces and with the braces on the wrong lines:

<?php

declare(strict_types=1);

namespace App\Model;

class CartService {
    public function getTotal(array $items): float {
        $total = 0;
        foreach ($items as $item) {
            $total = $total + $item['price'] * $item['quantity'];
        }
        return $total;
    }
}

The check command reports what breaks the standard and changes nothing:

dresscode check
app/Model/CartService.php
  error      1  `declare(strict_types=1)` must be on the line of the opening tag.                          file.strictTypes.position
  error      2  Expected 1 blank line before the namespace, 2 found.                                       blankLines.beforeNamespace
  error      6  Expected 2 blank lines before the class, 1 found.                                          blankLines.beforeDeclaration
  error   7:19  Expected a line break before the opening brace.                                            braces.position.class
  error      8  Expected the member indented by 1 tab, 4 spaces found.                                     indentation.unit
                Then also, on lines 9, 10, 13: Expected the statement indented by 2 tabs, 8 spaces found.  indentation.unit
                Then also, on line 11: Expected the statement indented by 3 tabs, 12 spaces found.         indentation.unit
                Then also, on line 12: Expected the closing brace indented by 2 tabs, 8 spaces found.      indentation.unit
                Then also, on line 14: Expected the closing brace indented by 1 tab, 4 spaces found.       indentation.unit
  error   8:51  Expected a line break before the opening brace.                                            braces.position.function
  error  11:13  The assignment must be written `+=` instead of repeating its target.                       expressions.assignment.targetInValue

FOUND  13 violations, 6 of them following from others, a fix leaves none in 1 file

Each finding gives the line (and column), says what is wrong, and ends with the name of the setting it breaks, such as braces.position.class. You will need that name when you want to adjust the standard. The lines starting with Then also belong to the finding above them; they are what follows from it. The fix command then repairs everything it can:

dresscode fix

And the class now looks like this:

<?php declare(strict_types=1);

namespace App\Model;


class CartService
{
	public function getTotal(array $items): float
	{
		$total = 0;
		foreach ($items as $item) {
			$total += $item['price'] * $item['quantity'];
		}
		return $total;
	}
}

Before you run fix for the first time, back up your files, or run it on a clean working tree so you can review the changes afterwards with git diff.

Adjusting the Standard

Every setting of the standard is a key of the configuration, and your dresscode.neon has the last word on each of them. Say your project wants one blank line between methods instead of two, and does not want == rewritten to ===:

blankLines:
	aroundMethods: 1

expressions:
	comparison:
		loose: keep

The value keep means “leave it the way the code has it”. What a key is for and what value it has in your project is printed by dresscode explain blankLines.aroundMethods. And when a single line has a good reason to break the standard, add a // dresscode:ignore comment to it.

Newer PHP and Nette

DressCode can do more than formatting. Add the modernizations set next to the standard, and it rewrites the code to what newer PHP offers, such as $user === null ? null : $user->getName() to $user?->getName(). It only goes as far as your composer.json allows:

use:
	- nette
	- modernizations

When you upgrade the Nette libraries, the dresscode/upgrade-nette package rewrites your code to their new API, see Upgrading Nette.

Continuous Integration

In a CI pipeline, install DressCode as a standalone project, so you decide which version runs:

- run: composer create-project dresscode/dresscode temp/dresscode ^1
- run: php temp/dresscode/bin/dresscode check

When check finds a violation, it exits with code 1 and the build fails. In GitHub Actions, the findings show up as annotations right in the pull request.

Moving from Version 3

The original nette/coding-standard package checked the standard with PHP CS Fixer and PHP CodeSniffer, through the ecs command and the ncs.php and ncs.xml files. It is abandoned in favor of DressCode, and its version 3 is the last one. To switch, create dresscode.neon as described above, write the adjustments you had in ncs.php and ncs.xml as its keys, and delete both files. dresscode config lists every key together with the value it has in your project.

The first dresscode fix will probably touch more files than you expect, because DressCode also fixes some places that version 3 left alone. Make it a commit of its own, with no other changes.

Everything else, from all the settings to running DressCode in your editor or after every edit an AI agent makes, is in the DressCode manual.