blankLines
Prázdné řádky tam, kde je standard chce: v hlavičce souboru kolem declare,
namespace a importů, ve třídě mezi metodami a členy, za otevírací a před zavírací závorkou bloku a kolem
příkazů jako return.
Opravuje · v presetech perCs, psr12, nette, symfony ·
pokrývá blank_line_after_namespace, blank_line_after_opening_tag,
blank_line_before_statement, blank_line_between_import_groups,
blank_lines_before_namespace, no_blank_lines_after_class_opening,
no_blank_lines_after_phpdoc, no_extra_blank_lines, single_line_after_imports,
PSR12.Classes.OpeningBraceSpace, PSR12.Files.FileHeader, PSR12.Files.OpenTag,
PSR12.Traits.UseDeclaration, PSR2.Methods.FunctionClosingBrace,
PSR2.Namespaces.UseDeclaration, SlevomatCodingStandard.Attributes.AttributeAndTargetSpacing,
SlevomatCodingStandard.Classes.ConstantSpacing,
SlevomatCodingStandard.Classes.EmptyLinesAroundClassBraces,
SlevomatCodingStandard.Classes.PropertySpacing, SlevomatCodingStandard.Classes.TraitUseSpacing,
SlevomatCodingStandard.ControlStructures.BlockControlStructureSpacing,
SlevomatCodingStandard.ControlStructures.JumpStatementsSpacing,
Squiz.WhiteSpace.ControlStructureSpacing,
Squiz.WhiteSpace.FunctionOpeningBraceSpace, Squiz.WhiteSpace.FunctionSpacing
Co pravidlo hlídá
Prázdné řádky jsou to, co dělá soubor čitelným na první pohled: hlavička oddělená od kódu, metody od sebe výrazně, vlastnosti a konstanty pohromadě, komentář přilepený k tomu, co popisuje. Všechna taková místa hlídá jedno pravidlo a každé z nich má vlastní volbu, ve čtyřech skupinách:
- hlavička souboru: za otevíracím tagem, kolem
namespace, za importy a mezi jejich skupinami, před první deklarací; - třída: mezi metodami (v rozhraní zvlášť), před první a za poslední metodou, před prvním a za posledním
členem, kolem
usetraitů, mezi vlastnostmi, konstantami a případy výčtu, před dokumentovaným členem a mezi dokumentačním komentářem či atributem a deklarací; - blok: za otevírací a před zavírací závorkou těla funkce nebo řídicí struktury, mezi větvemi
ifatrya mezi případyswitch; - příkazy: kolem třídy nebo funkce deklarované mezi příkazy, před příkazem daného druhu a za ním, třeba
prázdný řádek před
return.
Každá volba je buď počet prázdných řádků, nebo rozsah [min, max] s otevřeným koncem zapsaným jako
null, nebo keep, které dané místo nechá, jak je. Rozsah se hodí tam, kde chcete připustit dvojí
zápis: betweenMembers: [0, 1] dovolí psát vlastnosti těsně pod sebe i oddělené jedním řádkem, ale dva už
ne. Počet, který do rozsahu nespadá, pravidlo posune k nejbližší povolené hodnotě.
Výchozí hodnoty odpovídají stylu se dvěma prázdnými řádky mezi metodami. Preset psr12 nechává na
keep všechno, o čem PSR-12 mlčí (počet řádků mezi metodami a členy, kolem deklarací mezi příkazy, za
dokumentačním komentářem a za otevírací závorkou bloku), a mapu before vyprázdní; nette má
vlastní čísla pro hlavičku i třídu. Protože se mapa voleb slévá s presetem po klíčích, změníte jedno místo
jediným klíčem a ostatní zůstanou, jak je preset nastavil; testy s jinou hlavičkou dostanou jiné číslo v bloku for.
Příklad
class Cart
{
private array $items = []; // Expected 0 blank lines before the property, 1 found
public function add(Item $item): void // Expected 2 blank lines before the method, 0 found
{
$this->items[] = $item;
}
public function total(): int // Expected 2 blank lines before the method, 1 found
{
return array_sum($this->items);
}
}
class Cart
{
private array $items = [];
public function add(Item $item): void
{
$this->items[] = $item;
}
public function total(): int
{
return array_sum($this->items);
}
}
Volby: hlavička souboru
afterOpeningTag
Počet, rozsah nebo keep, výchozí 1. Za řádkem s <?php, na kterém pak žádný
kód nestojí. Soubor s HTML mimo PHP tagy nebo se zavíracím tagem ?> si svůj tag nechá. Styl, který píše
declare(strict_types=1) na řádek tagu, nastaví keep; tak to dělá nette.
<?php // Expected 1 blank line before the declare, 0 found
declare(strict_types=1);
<?php
declare(strict_types=1);
beforeNamespace
Počet, rozsah nebo keep, výchozí 1. Před deklarací jmenného prostoru.
<?php
declare(strict_types=1);
namespace App; // Expected 1 blank line before the namespace, 0 found
<?php
declare(strict_types=1);
namespace App;
afterNamespace
Počet, rozsah nebo keep, výchozí 1. Za deklarací jmenného prostoru bez složených závorek.
<?php
namespace App;
use App\Model\User; // Expected 1 blank line before the import, 0 found
<?php
namespace App;
use App\Model\User;
afterImports
Počet, rozsah nebo keep, výchozí 1. Za posledním importem, před zbytkem kódu.
<?php
namespace App;
use App\Model\User;
$user = new User; // Expected 1 blank line before the statement, 0 found
<?php
namespace App;
use App\Model\User;
$user = new User;
betweenImportGroups
Počet, rozsah nebo keep, výchozí 1. Mezi importy tříd, funkcí a konstant. Importy jedné
skupiny mezi sebou prázdný řádek nemají nikdy.
<?php
namespace App;
use App\Model\User;
use function App\format; // Expected 1 blank line before the import, 0 found
<?php
namespace App;
use App\Model\User;
use function App\format;
beforeDeclaration
Počet, rozsah nebo keep, výchozí keep. Před třídou, rozhraním, traitem, výčtem nebo funkcí,
která následuje hned za jmenným prostorem nebo za importy; tam nahrazuje afterNamespace a
afterImports. Hodnota keep tu ale místo nenechá, jak je: deklarace se pak řídí volbami
afterNamespace a afterImports stejně jako ostatní kód. Nette Coding Standard tu chce dva řádky, aby
deklarace od hlavičky odstoupila víc než kód:
rules:
blankLines:
beforeDeclaration: 2
<?php
namespace App;
use App\Model\User;
class Cart // Expected 2 blank lines before the class, 1 found
{
}
<?php
namespace App;
use App\Model\User;
class Cart
{
}
Volby: třída
betweenMethods
Počet, rozsah nebo keep, výchozí 2. Před metodou a za ní; první a poslední metoda třídy se
řídí volbami beforeFirstMethod a afterLastMethod. Funkce deklarované mimo třídu řídí betweenDeclarations.
rules:
blankLines:
betweenMethods: 1
class Cart
{
public function add(Item $item): void
{
}
public function total(): int // Expected 1 blank line before the method, 2 found
{
}
}
class Cart
{
public function add(Item $item): void
{
}
public function total(): int
{
}
}
betweenInterfaceMethods
Počet, rozsah nebo keep, výchozí 1. V rozhraní nahrazuje betweenMethods, platí
tedy před metodou a za ní, i když je sousedním členem konstanta. Metody rozhraní nemají tělo, a stačí jim proto menší
odstup.
rules:
blankLines:
betweenInterfaceMethods: 0
interface Storage
{
public function read(string $key): mixed;
public function write(string $key, mixed $value): void; // Expected 0 blank lines before the method, 1 found
}
interface Storage
{
public function read(string $key): mixed;
public function write(string $key, mixed $value): void;
}
beforeFirstMethod
Počet, rozsah nebo keep, výchozí 0. Před metodou, která je prvním členem třídy.
rules:
blankLines:
beforeFirstMethod: 1
class Cart
{
public function add(Item $item): void // Expected 1 blank line before the method, 0 found
{
}
}
class Cart
{
public function add(Item $item): void
{
}
}
afterLastMethod
Počet, rozsah nebo keep, výchozí 0. Za metodou, která je posledním členem třídy.
rules:
blankLines:
afterLastMethod: 1
class Cart
{
public function add(Item $item): void
{
}
} // Expected 1 blank line after the method, 0 found
class Cart
{
public function add(Item $item): void
{
}
}
beforeFirstMember
Počet, rozsah nebo keep, výchozí 0. Před prvním členem třídy, pokud to není metoda; pak
platí beforeFirstMethod.
rules:
blankLines:
beforeFirstMember: 1
class Cart
{
private array $items = []; // Expected 1 blank line before the property, 0 found
}
class Cart
{
private array $items = [];
}
afterLastMember
Počet, rozsah nebo keep, výchozí 0. Za posledním členem třídy, pokud to není metoda; pak
platí afterLastMethod.
rules:
blankLines:
afterLastMember: 1
class Cart
{
private array $items = [];
} // Expected 1 blank line before the closing brace, 0 found
class Cart
{
private array $items = [];
}
betweenTraitUses
Počet, rozsah nebo keep, výchozí 0. Mezi use traitů na začátku třídy.
class Cart
{
use Countable;
use Serializable; // Expected 0 blank lines before the trait use, 1 found
}
class Cart
{
use Countable;
use Serializable;
}
afterTraitUses
Počet, rozsah nebo keep, výchozí 1. Před členem, který následuje za use traitů,
i když je to metoda.
class Cart
{
use Countable;
private array $items = []; // Expected 1 blank line before the property, 0 found
}
class Cart
{
use Countable;
private array $items = [];
}
betweenMembers
Počet, rozsah nebo keep, výchozí [0, 1]. Mezi vlastnostmi, konstantami a případy výčtu bez
dokumentačního komentáře a atributu. Výchozí rozsah dovolí členy psát těsně pod sebe i oddělené jedním
řádkem.
class Cart
{
private array $items = [];
private int $count = 0;
private ?Customer $customer = null; // Expected at most 1 blank line before the property, 2 found
}
class Cart
{
private array $items = [];
private int $count = 0;
private ?Customer $customer = null;
}
S pevným počtem musí být odstup všude stejný:
rules:
blankLines:
betweenMembers: 1
class Cart
{
private array $items = [];
private int $count = 0; // Expected 1 blank line before the property, 0 found
}
class Cart
{
private array $items = [];
private int $count = 0;
}
beforeDocumentedMember
Počet, rozsah nebo keep, výchozí 1. Před vlastností, konstantou nebo případem výčtu, který
má dokumentační komentář nebo atribut; komentář potřebuje odstup od předchozího člena, aby bylo vidět, ke
kterému patří.
class Cart
{
private array $items = [];
/** @var int<0, max> */
private int $count = 0; // Expected 1 blank line before the property, 0 found
}
class Cart
{
private array $items = [];
/** @var int<0, max> */
private int $count = 0;
}
afterPhpdoc
Počet, rozsah nebo keep, výchozí 0. Mezi dokumentačním komentářem nebo atributem a deklarací,
ke které patří. Dokumentační komentář hned za <?php na začátku souboru patří souboru, takže se ho
volba netýká.
class Cart
{
/**
* Adds an item.
*/
public function add(Item $item): void // Expected 0 blank lines after the doc comment, 1 found
{
}
}
class Cart
{
/**
* Adds an item.
*/
public function add(Item $item): void
{
}
}
Volby: blok
afterBlockOpeningBrace
Počet, rozsah nebo keep, výchozí 0. Za otevírací závorkou těla funkce, řídicí struktury,
switch nebo match.
function add(Item $item): void
{
$this->items[] = $item; // Expected 0 blank lines after the opening brace, 1 found
}
function add(Item $item): void
{
$this->items[] = $item;
}
beforeBlockClosingBrace
Počet, rozsah nebo keep, výchozí keep. Před zavírací závorkou bloku. Výchozí je
keep, protože prázdný řádek před } bývá záměrný oddělovač větví v řetězu
} catch nebo } else; kdo ho nechce nikde, nastaví nulu.
rules:
blankLines:
beforeBlockClosingBrace: 0
function add(Item $item): void
{
$this->items[] = $item;
} // Expected 0 blank lines before the closing brace, 1 found
function add(Item $item): void
{
$this->items[] = $item;
}
betweenBranches
Počet, rozsah, keep nebo lastSetApart, výchozí keep. Před zavírací závorkou
větve if nebo try, za kterou pokračuje else, elseif, catch nebo
finally; na tomto místě má přednost před beforeBlockClosingBrace. Hodnota lastSetApart
dá jeden prázdný řádek za větev, jejíž poslední příkaz je od předchozích oddělený prázdným řádkem; bez něj by
se takový příkaz opticky přilepil k } else pod sebou. Totéž platí o větvi zakončené komentářem
odděleným prázdným řádkem. Ostatní větve téhož řetězu nechá, jak jsou. Tuto hodnotu volí nette.
rules:
blankLines:
betweenBranches: lastSetApart
if ($order->isPaid()) {
$this->ship($order);
return;
} elseif ($order->isExpired()) { // Expected 1 blank line before the closing brace, 0 found
$this->cancel($order);
} else {
$this->remind($order);
}
if ($order->isPaid()) {
$this->ship($order);
return;
} elseif ($order->isExpired()) {
$this->cancel($order);
} else {
$this->remind($order);
}
betweenCases
Počet, rozsah, keep nebo lastSetApart, výchozí keep. Před case nebo
default ve switch, kterému předchází případ s příkazy; skupina case 1:
case 2: bez příkazů zůstává pohromadě. Hodnota lastSetApart dá jeden prázdný řádek za
případ, jehož poslední příkaz, typicky break, je od předchozích oddělený prázdným řádkem, a ostatní
nechá, jak jsou. Komentář hned pod příkazy, třeba // no break, patří k případu nad ním, takže prázdný
řádek jde pod něj; komentář oddělený prázdným řádkem patří k case pod ním. Tuto hodnotu volí
nette.
rules:
blankLines:
betweenCases: lastSetApart
switch ($status) {
case Status::New:
$this->validate($order);
break;
case Status::Paid: // Expected 1 blank line before the case, 0 found
$this->ship($order);
break;
}
switch ($status) {
case Status::New:
$this->validate($order);
break;
case Status::Paid:
$this->ship($order);
break;
}
Volby: příkazy
betweenDeclarations
Počet, rozsah nebo keep, výchozí 2. Před třídou, rozhraním, traitem, výčtem nebo funkcí
deklarovanou mezi příkazy a za ní, tedy všude, kde o odstupu nerozhoduje hlavička souboru (beforeDeclaration,
afterNamespace, afterImports). Patří sem i deklarace uvnitř podmínky. nette dovoluje
jeden nebo dva řádky ([1, 2]), symfony žádný nebo jeden ([0, 1]).
function format(string $s): string
{
return trim($s);
}
class Cart // Expected 2 blank lines before the class, 0 found
{
}
echo format('x'); // Expected 2 blank lines after the class, 0 found
function format(string $s): string
{
return trim($s);
}
class Cart
{
}
echo format('x');
before
Mapa druh příkazu → počet, rozsah nebo keep, výchozí {"return":[1,null]}: před
return je aspoň jeden prázdný řádek, pokud není prvním příkazem bloku. Druhů je dvanáct a jiný klíč
schéma odmítne: break, continue, do, for, foreach,
if, return, switch, throw, try, while a
yield, které znamená příkaz tvořený výrazem yield nebo yield from. Volba se
neuplatní, když je sousedním příkazem deklarace třídy nebo funkce, use, namespace,
declare nebo HTML mimo PHP tagy; odstup od nich řídí volby hlavičky a betweenDeclarations. Presety
podle specifikací PER Coding Style a PSR-12 mapu vyprázdní, protože o prázdných řádcích mezi příkazy
neříkají nic.
function total(array $items): int
{
$sum = array_sum($items);
return $sum; // Expected at least 1 blank line before the return, 0 found
}
function total(array $items): int
{
$sum = array_sum($items);
return $sum;
}
after
Mapa druh příkazu → počet, rozsah nebo keep, výchozí []. Za příkazem daného druhu, před
dalším příkazem bloku, se stejnými výjimkami jako u before.
rules:
blankLines:
after: {if: 1}
if ($item->isFree()) {
return;
}
$this->items[] = $item; // Expected 1 blank line after the if, 0 found
if ($item->isFree()) {
return;
}
$this->items[] = $item;
Související pravidla
- bracesPosition rozhoduje o zalomení řádku u složených závorek; tohle pravidlo o prázdných řádcích za nimi
singleStatementPerLinedá každému příkazu vlastní řádek, teprve pak mezi nimi mají prázdné řádky smysl
Zdroj
Třída BlankLinesRule, fixtury blankLines.