
2024-05-10
PER-2 на русском
2023-10-30
Приветствую, друзья!
Данная статья является переводом с официальной страницы стандарта PER-2 по стилям написания кода на языке PHP. Ссылку на оригинал статьи вы сможете найти в самом низу статьи. Приятного чтения!
Ключевые слова «ДОЛЖЕН», «НЕ ДОЛЖЕН», «ТРЕБУЕТСЯ», «СЛЕДУЕТ», «НЕ СЛЕДУЕТ», «РЕКОМЕНДУЕТСЯ», «МОЖЕТ» и «ВОЗМОЖНО» в этом документе: интерпретироваться, как описано в RFC 2119.
Эта спецификация расширяет и заменяет PSR-12 расширенное руководство по стилю написания кода, и требует соблюдения PSR-1, основного стандарта написания кода.
Как и PSR-12, цель этой спецификации — уменьшить когнитивные трудности при ревью кода разных авторов. Это делается путем перечисления общего набора правил и ожиданий относительно форматирования кода PHP. Этот PSR стремится предоставить набор правил, которые инструменты соблюдения стиля написания кода могут использовать, которыми можно декларировать проекты, к которым разработчики могут легко апеллировать и при взаимодействии между различными проектами. Когда разные авторы сотрудничают в нескольких проектах, полезно иметь один набор рекомендаций, который можно использовать во всех этих проектах. Таким образом, преимущество этого руководства заключается не в самих правилах, а в их распространении.
PSR-12 был принят в 2019 году, и с тех пор в PHP был внесен ряд изменений, которые влияют на рекомендации по стилю написания кода. Несмотря на то, что PSR-12 очень обширен, из функциональных возможностей PHP, существовавших на момент написания, новые функциональные возможности очень открыты для интерпретации. Таким образом, этот PER направлен на разъяснение содержания PSR-12 в более современном контексте, с доступными новыми функциями, внесение корректировок в PSR-12 и дальнейшее обновление его в соответствии с новыми данными и языковыми изменениями.
В этом документе любые инструкции МОГУТ быть проигнорированы, если они не существуют в версиях PHP, поддерживаемых вашим проектом.
Этот пример включает в себя некоторые из приведенных ниже правил в качестве краткого обзора:
<?php
declare(strict_types=1);
namespace Vendor\Package;
use Vendor\Package\{ClassA as A, ClassB, ClassC as C};
use Vendor\Package\SomeNamespace\ClassD as D;
use function Vendor\Package\{functionA, functionB, functionC};
use const Vendor\Package\{ConstantA, ConstantB, ConstantC};
class Foo extends Bar implements FooInterface
{
public function sampleFunction(int $a, int $b = null): array
{
if ($a === $b) {
bar();
} elseif ($a > $b) {
$foo->bar($arg1);
} else {
BazClass::bar($arg2, $arg3);
}
}
final public static function bar()
{
// тело метода
}
}
enum Beep: int
{
case Foo = 1;
case Bar = 2;
public function isOdd(): bool
{
return $this->value() % 2;
}
}
Код ДОЛЖЕН соответствовать всем правилам, изложенным в PSR-1.
Термин «StudlyCaps» в PSR-1 ДОЛЖЕН интерпретироваться как PascalCase, где первая буква каждого слова пишется с заглавной буквы, включая самую первую букву.
Все файлы PHP ДОЛЖНЫ использовать только окончание строки Unix LF (перевод строки).
Все файлы PHP ДОЛЖНЫ заканчиваться непустой строкой, заканчивающейся одним LF.
Закрывающий тег ?> ДОЛЖЕН быть опущен в файлах, содержащих только PHP.
НЕ ДОЛЖНО быть жесткого ограничения на длину строки.
Мягкое ограничение длины строки ДОЛЖНО составлять 120 символов.
Строкам НЕ СЛЕДУЕТ быть длиннее 80 символов; строки длиннее этого СЛЕДУЕТ разбивать на несколько последующих строк длиной не более 80 символов каждая.
В конце строк НЕ ДОЛЖНО быть пробелов.
Пустые строки МОГУТ быть добавлены для улучшения читаемости и обозначения связанных блоков кода, за исключением случаев, когда это явно запрещено.
НЕ ДОЛЖНО быть более одной инструкции в строке. ( Под инструкцией имеется в виду например такое выражение $a = $b + $c; или любая другая инструкция заканчивающаяся символом ; )
Код ДОЛЖЕН использовать отступ в 4 пробела для каждого уровня отступа и НЕ ДОЛЖЕН использовать для отступов табуляцию. ( 1 табуляция в IDE должна быть настроена именно как 4 пробельных символа, а не 1 таб-сдвиг )
Все зарезервированные ключевые слова и типы в PHP [1][2] должны быть в нижнем регистре.
Любые новые типы и ключевые слова, добавленные в будущие версии PHP, ДОЛЖНЫ быть написаны в нижнием регистре.
Короткая форма ключевых слов ДОЛЖНА использоваться, например bool вместо boolean, int вместо integer и т.д.
Многочисленные конструкции PHP позволяют разделять последовательность значений запятой, а последний элемент может иметь необязательную запятую. Примеры включают пары ключ/значение массива, аргументы функции, операторы использования замыкания, ветки операторов match() и т. д.
Если этот список содержится в одной строке, то последний элемент НЕ ДОЛЖЕН иметь завершающую запятую.
Если список разделен на несколько строк, последний элемент ДОЛЖЕН иметь завершающую запятую.
Ниже приведены примеры правильной расстановки запятых:
function beep(string $a, string $b, string $c)
{
// ...
}
function beep(
string $a,
string $b,
string $c,
) {
// ...
}
$arr = ['a' => 'A', 'b' => 'B', 'c' => 'C'];
$arr = [
'a' => 'A',
'b' => 'B',
'c' => 'C',
];
$result = match ($a) {
'foo' => 'Foo',
'bar' => 'Bar',
default => 'Baz',
};
Заголовок файла PHP может состоять из нескольких разных блоков. Если они присутствуют, каждый из приведенных ниже блоков ДОЛЖЕН быть разделен одной пустой строкой и НЕ ДОЛЖЕН содержать пустую строку. Каждый блок ДОЛЖЕН располагаться в порядке, указанном ниже, хотя ненужные блоки могут быть опущены.
Если файл содержит смесь HTML и PHP, любой из вышеперечисленных разделов по-прежнему можно использовать. Если так, то они ДОЛЖНЫ присутствовать в верхней части файла, даже если остальная часть кода состоит из закрывающего тега PHP, а затем из смеси HTML и PHP.
Когда открывающий тег <?php находится в первой строке файла, он ДОЛЖЕН находиться в отдельной строке без каких-либо других операторов, если только это не файл, содержащий разметку вне открывающих и закрывающих тегов PHP.
Операторы импорта никогда не ДОЛЖНЫ начинаться с обратной косой черты в начале, поскольку они всегда должны быть полными.
Следующий пример иллюстрирует полный список всех блоков:
<?php
/**
* Этот файл содержит пример стандарта написания кода
*/
declare(strict_types=1);
namespace Vendor\Package;
use Vendor\Package\{ClassA as A, ClassB, ClassC as C};
use Vendor\Package\SomeNamespace\ClassD as D;
use Vendor\Package\AnotherNamespace\ClassE as E;
use SomeVendor\Pack\ANamespace\SubNamespace\ClassF;
use function Vendor\Package\{functionA, functionB, functionC};
use function Another\Vendor\functionD;
use const Vendor\Package\{CONSTANT_A, CONSTANT_B, CONSTANT_C};
use const Another\Vendor\CONSTANT_D;
/**
* FooBar is an example class.
*/
class FooBar
{
// ... дополнительный код PHP ...
}
При использовании составных пространств имен в группе НЕ ДОЛЖНО быть более двух подпространств имен. То есть допускается следующее:
<?php
use Vendor\Package\SomeNamespace\{
SubnamespaceOne\ClassA,
SubnamespaceOne\ClassB,
SubnamespaceTwo\ClassY,
ClassZ,
};
И не будет разрешено следующее:
<?php
use Vendor\Package\SomeNamespace\{
//This has too many namespace segments to be in a group.
SubnamespaceOne\AnotherNamespace\ClassA,
SubnamespaceOne\ClassB,
ClassZ,
};
При желании объявить строгие типы в файлах, содержащих разметку вне открывающих и закрывающих тегов PHP, объявление ДОЛЖНО находиться в первой строке файла и включать открывающий тег PHP, объявление строгих типов и закрывающий тег.
Например:
<?php declare(strict_types=1) ?>
<html>
<body>
<?php
// ... additional PHP code ...
?>
</body>
</html>
Операторы declare НЕ ДОЛЖНЫ содержать пробелов и ДОЛЖНЫ быть объявлены точно как указано: (strict_types=1) (с необязательным разделителем точкой с запятой).
Операторы declare ДОЛЖНЫ быть отформатированы, как показано ниже. Обратите внимание на положение скобок и пробелов:
declare(ticks=1) {
// some code
}
Термин «класс» относится ко всем классам, интерфейсам, признакам и перечислениям.
За закрывающей скобкой НЕ ДОЛЖЕН следовать какой-либо комментарий или утверждение в той же строке.
При создании экземпляра нового класса круглые скобки ДОЛЖНЫ присутствовать всегда, даже если в конструктор не переданы аргументы. Например:
new Foo();
Если класс не содержит дополнительных объявлений (например, исключение, которое существует только для расширения другого исключения новым типом), то тело класса СЛЕДУЕТ сократить до {} и поместить в ту же строку, что и предыдущий символ, разделив его символом пробела. Например:
class MyException extends \RuntimeException {}
Ключевые слова extends и implements ДОЛЖНЫ быть объявлены в той же строке, что и имя класса.
Открывающая скобка класса ДОЛЖНА располагаться на отдельной строке, и ей НЕ ДОЛЖНА предшествовать или следовать пустая строка.
Закрывающая скобка класса ДОЛЖНА идти на отдельной строке, сразу после последней строки тела класса, и ей НЕ ДОЛЖНА предшествовать пустая строка.
Ниже приведен правильно отформатированный класс:
<?php
namespace Vendor\Package;
use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
class ClassName extends ParentClass implements \ArrayAccess, \Countable
{
// constants, properties, methods
}
Списки импленетаций интерфейсов, а так же расширений (в случае интерфейсов) МОГУТ быть разделены на несколько строк, где каждая последующая строка имеет один отступ. При этом первый элемент в списке ДОЛЖЕН находиться на следующей строке, и в каждой строке ДОЛЖЕН быть только один интерфейс. Например:
<?php
namespace Vendor\Package;
use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
class ClassName extends ParentClass implements
\ArrayAccess,
\Countable,
\Serializable
{
// constants, properties, methods
}
Ключевое слово use, используемое внутри класса для подключения трейта ДОЛЖНО быть расположено на строке, следующей за открывающей скобкой.
Каждый отдельный трейт, импортируемый в класс, ДОЛЖЕН быть подключаться по одному в строке, и каждое подключение ДОЛЖНО иметь свой собственный оператор use.
Ниже приведен правильный пример использования трейта.
<?php
namespace Vendor\Package;
use Vendor\Package\FirstTrait;
use Vendor\Package\SecondTrait;
use Vendor\Package\ThirdTrait;
class ClassName
{
use FirstTrait;
use SecondTrait;
use ThirdTrait;
}
Если после оператора use в классе ничего нет, закрывающая скобка класса ДОЛЖНА находиться на следующей строке после оператора use. Например:
<?php
namespace Vendor\Package;
use Vendor\Package\FirstTrait;
class ClassName
{
use FirstTrait;
}
В противном случае ДОЛЖНА быть пустая строка после оператора импорта, как в примере ниже:
<?php
namespace Vendor\Package;
use Vendor\Package\FirstTrait;
class ClassName
{
use FirstTrait;
private $property;
}
При использовании операторов insteadof и as их следует использовать следующим образом, принимая во внимание отступы, интервалы и новые строки.
<?php
class Talker
{
use A;
use B {
A::smallTalk insteadof B;
}
use C {
B::bigTalk insteadof C;
C::mediumTalk as FooBar;
}
}
Область видимости ДОЛЖНА быть объявлена у всех свойств.
Область видимости ДОЛЖНА быть объявлена у всех константа в случае, если ваш продукт написан на версии PHP7.1 и выше.
Ключевое слово var НЕ ДОЛЖНО использоваться для объявления свойств.
На одной строке не должно быть объявлено более одного свойства.
Имена свойств НЕ ДОЛЖНЫ начинаться с одного подчеркивания, чтобы указать на защищенную или приватную область видимости. То есть префикс подчеркивания явно не имеет значения.
Между объявлением типа и именем свойства ДОЛЖЕН быть пробел.
Объявление свойства выглядит следующим образом:
<?php
namespace Vendor\Package;
class ClassName
{
public $foo = null;
public static int $bar = 0;
}
Область видимости ДОЛЖНА быть объявлена для всех методов.
Имена методов НЕ ДОЛЖНЫ начинаться с одного подчеркивания, чтобы указать на защищенную или приватную область видимости. То есть префикс подчеркивания явно не имеет значения.
Имена методов и функций НЕ ДОЛЖНЫ объявляться с пробелом после имени метода. Открывающая скобка ДОЛЖНА идти на отдельной строке, а закрывающая скобка ДОЛЖНА идти на следующую строку после тела. НЕ ДОЛЖНО быть пробела после открывающей скобки и НЕ ДОЛЖНО быть пробела перед закрывающей скобкой.
Объявление метода выглядит следующим образом. Обратите внимание на размещение круглых скобок, запятых, пробелов и фигурных скобок:
<?php
namespace Vendor\Package;
class ClassName
{
public function fooBarBaz($arg1, &$arg2, $arg3 = [])
{
// тело метода
}
}
Объявление функции выглядит следующим образом. Обратите внимание на размещение круглых скобок, запятых, пробелов и фигурных скобок:
<?php
function fooBarBaz($arg1, &$arg2, $arg3 = [])
{
// тело функции
}
Если функция или метод не содержит операторов или комментариев (например, пустая реализация без операций или при использовании продвижения свойства конструктора), то тело СЛЕДУЕТ сокращать до {} и помещать в ту же строку, что и предыдущий символ, разделяя его символом пробела. Например:
class Point
{
public function __construct(private int $x, private int $y) {}
// ...
}
class Point
{
public function __construct(
public readonly int $x,
public readonly int $y,
) {}
}
В списке аргументов НЕ ДОЛЖНО быть пробела перед каждой запятой и ДОЛЖЕН быть один пробел после каждой запятой.
Аргументы метода и функции со значениями по умолчанию ДОЛЖНЫ располагаться в конце списка аргументов.
<?php
namespace Vendor\Package;
class ClassName
{
public function foo(int $arg1, &$arg2, $arg3 = [])
{
// тело метода
}
}
Списки аргументов МОГУТ быть разделены на несколько строк, при этом каждая последующая строка имеет один отступ ( 1 табуляцию ). При этом первый элемент в списке ДОЛЖЕН находиться на следующей строке, и в каждой строке ДОЛЖЕН быть только один аргумент.
Когда список аргументов разбит на несколько строк, закрывающаяся и открывающая скобки ДОЛЖНЫ располагаться вместе на отдельной строке с одним пробелом между ними. Например:
<?php
namespace Vendor\Package;
class ClassName
{
public function aVeryLongMethodName(
ClassTypeHint $arg1,
&$arg2,
array $arg3 = [],
) {
// тело метода
}
}
Если у вас есть строгая типизация возвращаемого значения, то ДОЛЖЕН быть один пробел после двоеточия, за которым следует объявление типа. Двоеточие и строгая типизация возвращаемого значения ДОЛЖНЫ находиться в той же строке, что и закрывающая скобка списка аргументов ( в случае, если список аргументов располагается на нескольких строках ), без пробелов между двумя символами. Например:
<?php
declare(strict_types=1);
namespace Vendor\Package;
class ReturnTypeVariations
{
public function functionName(int $arg1, $arg2): string
{
return 'foo';
}
public function anotherFunction(
string $foo,
string $bar,
int $baz,
): string {
return 'foo';
}
}
В объявлениях типов, допускающих значение NULL, НЕ ДОЛЖНО быть пробела между вопросительным знаком и типом. Например:
<?php
declare(strict_types=1);
namespace Vendor\Package;
class ReturnTypeVariations
{
public function functionName(?string $arg1, ?int &$arg2): ?string
{
return 'foo';
}
}
При использовании оператора ссылки & перед аргументом НЕ ДОЛЖНО быть пробела после него, как в предыдущем примере.
НЕ ДОЛЖНО быть пробела между вариативным трехточечным оператором и именем аргумента:
public function process(string $algorithm, ...$parts)
{
// processing
}
При объединении ссылочного оператора и вариативного трехточечного оператора НЕ ДОЛЖНО быть пробела между ними:
public function process(string $algorithm, &...$parts)
{
// processing
}
Классы, свойства и методы имеют множество ключевых слов модификаторов, которые изменяют способ их обработки движком и языком. Если они присутствуют, они ДОЛЖНЫ быть в следующем порядке:
Все ключевые слова ДОЛЖНЫ быть в одной строке и ДОЛЖНЫ быть разделены одним пробелом.
Ниже приведен правильный пример использования ключевого слова-модификатора:
<?php
namespace Vendor\Package;
abstract class ClassName
{
protected static readonly string $foo;
final protected int $beep;
abstract protected function zim();
final public static function bar()
{
// method body
}
}
readonly class ValueObject
{
// ...
}
При вызове метода или функции НЕ ДОЛЖНО быть пробела между именем метода или функции и открывающей скобкой, НЕ ДОЛЖНО быть пробела после открывающей скобки и НЕ ДОЛЖНО быть пробела перед закрывающей круглой скобкой. В списке аргументов НЕ ДОЛЖНО быть пробела перед каждой запятой и ДОЛЖЕН быть один пробел после каждой запятой.
Следующие строки показывают правильные вызовы:
<?php
bar();
$foo->bar($arg1);
Foo::bar($arg2, $arg3);
Списки аргументов МОГУТ быть разделены на несколько строк, при этом каждая последующая строка имеет один отступ ( табуляцию ). При этом первый элемент в списке ДОЛЖЕН находиться на следующей строке, и в каждой строке ДОЛЖЕН быть только один аргумент. Разделение одного аргумента на несколько строк (как это может быть в случае с замыканием или массивом) не означает разделения самого списка аргументов.
Следующие примеры показывают правильное использование аргументов.
<?php
$foo->bar(
$longArgument,
$longerArgument,
$muchLongerArgument,
);
<?php
somefunction($foo, $bar, [
// ...
], $baz);
$app->get('/hello/{name}', function ($name) use ($app) {
return 'Hello ' . $app->escape($name);
});
При использовании именованных аргументов НЕ ДОЛЖНО быть пробела между именем аргумента и двоеточием, а между двоеточием и значением аргумента ДОЛЖЕН быть один пробел. Например:
somefunction($a, b: $b, c: 'c');
Цепочка методов МОЖЕТ быть помещена в отдельные строки, где каждая последующая строка имеет один отступ. При этом первый метод ДОЛЖЕН находиться на следующей строке. Например:
$someInstance
->create()
->prepare()
->run();
На функцию или метод можно ссылаться таким образом, чтобы создать замыкание, предоставляя ... вместо аргументов.
Если да, то ... НЕ ДОЛЖНО содержать пробелов до или после. То есть правильный формат — foo(...).
Общие правила стиля управляющих структур следующие:
Тело каждой структуры ДОЛЖНО быть заключено в фигурные скобки. Это стандартизирует внешний вид структур и снижает вероятность появления ошибок при добавлении новых строк в тело.
Структура if выглядит следующим образом. Обратите внимание на размещение круглых скобок, пробелов и фигурных скобок; и что else и elseif находятся на той же строке, что и закрывающая скобка предыдущего тела.
<?php
if ($expr1) {
// if body
} elseif ($expr2) {
// elseif body
} else {
// else body;
}
Ключевое слово elseif СЛЕДУЕТ использовать вместо else if, чтобы все ключевые слова управления выглядели как отдельные слова.
Выражения в круглых скобках МОГУТ быть разделены на несколько строк, при этом каждая последующая строка имеет отступ ( табуляцию ) хотя бы один раз. При этом первое условие ДОЛЖНО находиться на следующей строке за ключевым словом. Закрывающая и открывающая скобки ДОЛЖНЫ располагаться вместе на отдельной строке с одним пробелом между ними. Логические операторы между условиями ДОЛЖНЫ всегда находиться в начале или в конце строки ( нужно выбрать один стиль и его придерживаться ).
Например:
<?php
if (
$expr1
&& $expr2
) {
// if body
} elseif (
$expr3
&& $expr4
) {
// elseif body
}
Структура switch выглядит следующим образом. Обратите внимание на размещение круглых скобок, пробелов и фигурных скобок. Оператор case ДОЛЖЕН иметь один отступ от переключателя, а ключевое слово break (или другие завершающие ключевые слова) ДОЛЖНО иметь отступ на том же уровне, что и тело варианта. Если отсутствие завершающей конструкции предусмотрено намеренно в непустом теле регистра, то ДОЛЖЕН быть комментарий типа "// no break".
<?php
switch ($expr) {
case 0:
echo 'First case, with a break';
break;
case 1:
echo 'Second case, which falls through';
// no break
case 2:
case 3:
case 4:
echo 'Third case, return instead of break';
return;
default:
echo 'Default case';
break;
}
Выражения в круглых скобках МОГУТ быть разделены на несколько строк, при этом каждая последующая строка имеет отступ хотя бы один раз. При этом первое условие ДОЛЖНО находиться на следующей строке относительно ключевого слова. Закрывающая и открывающая скобки ДОЛЖНЫ располагаться вместе на отдельной строке с одним пробелом между ними. Логические операторы между условиями ДОЛЖНЫ всегда находиться в начале или в конце строки ( нужно выбрать один стиль и его придерживаться ).
Например:
<?php
switch (
$expr1
&& $expr2
) {
// structure body
}
Аналогично, выражение match выглядит следующим образом. Обратите внимание на размещение круглых скобок, пробелов и фигурных скобок.
<?php
$returnValue = match ($expr) {
0 => 'First case',
1, 2, 3 => multipleCases(),
default => 'Default case',
};
Оператор while выглядит следующим образом. Обратите внимание на размещение круглых скобок, пробелов и фигурных скобок.
<?php
while ($expr) {
// structure body
}
Выражения в круглых скобках МОГУТ быть разделены на несколько строк, при этом каждая последующая строка имеет отступ хотя бы один раз. При этом первое условие ДОЛЖНО находиться на следующей строке. Закрывающая и открывающая скобки ДОЛЖНЫ располагаться вместе на отдельной строке с одним пробелом между ними. Логические операторы между условиями ДОЛЖНЫ всегда находиться в начале или в конце строки ( нужно выбрать один стиль и его придерживаться ).
<?php
while (
$expr1
&& $expr2
) {
// structure body
}
Аналогично, оператор do while выглядит следующим образом. Обратите внимание на размещение круглых скобок, пробелов и фигурных скобок.
<?php
do {
// structure body;
} while ($expr);
Выражения в круглых скобках МОГУТ быть разделены на несколько строк, при этом каждая последующая строка имеет отступ хотя бы один раз. При этом первое условие ДОЛЖНО находиться на следующей строке. Логические операторы между условиями ДОЛЖНЫ всегда находиться в начале или в конце строки ( нужно выбрать один стиль и его придерживаться ). Например:
<?php
do {
// structure body;
} while (
$expr1
&& $expr2
);
Оператор for выглядит следующим образом. Обратите внимание на размещение круглых скобок, пробелов и фигурных скобок.
<?php
for ($i = 0; $i < 10; $i++) {
// for body
}
Выражения в круглых скобках МОГУТ быть разделены на несколько строк, при этом каждая последующая строка имеет отступ хотя бы один раз. При этом первое выражение ДОЛЖНО находиться на следующей строке. Закрывающая и открывающая скобки ДОЛЖНЫ располагаться вместе на отдельной строке с одним пробелом между ними. Например:
<?php
for (
$i = 0;
$i < 10;
$i++
) {
// for body
}
Оператор foreach выглядит следующим образом. Обратите внимание на размещение круглых скобок, пробелов и фигурных скобок.
<?php
foreach ($iterable as $key => $value) {
// foreach body
}
Блок try-catch-finally выглядит следующим образом. Обратите внимание на размещение круглых скобок, пробелов и фигурных скобок.
<?php
try {
// try body
} catch (FirstThrowableType $e) {
// catch body
} catch (OtherThrowableType | AnotherThrowableType $e) {
// catch body
} finally {
// finally body
}
Правила стиля для операторов сгруппированы по арности (количеству принимаемых ими операндов).
Если вокруг оператора разрешены пробелы, то для удобства чтения МОГУТ использоваться несколько пробелов.
Все операторы, не описанные здесь, могут быть стилизованы на ваше усмотрение.
Операторы инкремента/декремента НЕ ДОЛЖНЫ иметь пробела между оператором и операндом:
$i++;
++$j;
Операторы приведения типов НЕ ДОЛЖНЫ содержать пробелов в круглых скобках и ДОЛЖНЫ быть отделены от переменной, с которой они работают, ровно одним пробелом:
$intValue = (int) $input;
У всех бинарных arithmetic, comparison, assignment, bitwise, logical, string, и type операторов спереди и сзади ДОЛЖЕН быть хотя бы один пробел:
if ($a === $b) {
$foo = $bar ?? $a ?? $b;
} elseif ($a > $b) {
$foo = $a + $b * $c;
}
В условном операторе, также известном как тернарный оператор, перед и после символов ? и : должен быть как минимум один пробел:
$variable = $foo ? 'foo' : 'bar';
Если средний операнд условного оператора отсутствует, оператор ДОЛЖЕН следовать тем же правилам стиля, что и другие операторы двоичного сравнения:
$variable = $foo ?: 'bar';
Замыкания, также известные как анонимные функции, ДОЛЖНЫ быть объявлены с пробелом после ключевого слова function, а также с пробелом до и после ключевого слова use.
Открывающая скобка ДОЛЖНА идти на той же строке, а закрывающая скобка ДОЛЖНА идти на следующую строку после тела.
НЕ ДОЛЖНО быть пробела после открывающей круглой скобки списка аргументов или списка переменных, и НЕ ДОЛЖНО быть пробела перед закрывающей круглой скобкой списка аргументов или списка переменных.
В списке аргументов и списке переменных НЕ ДОЛЖНО быть пробела перед каждой запятой и ДОЛЖЕН быть один пробел после каждой запятой.
Аргументы закрытия со значениями по умолчанию ДОЛЖНЫ располагаться в конце списка аргументов.
Если тип возвращаемого значения присутствует, он ДОЛЖЕН следовать тем же правилам, что и обычные функции и методы; если ключевое слово use присутствует, двоеточие ДОЛЖНО следовать за закрывающими круглыми скобками списка использования без пробелов между двумя символами.
Замыкание выглядит следующим образом. Обратите внимание на размещение круглых скобок, запятых, пробелов и фигурных скобок:
<?php
$closureWithArgs = function ($arg1, $arg2) {
// body
};
$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {
// body
};
$closureWithArgsVarsAndReturn = function ($arg1, $arg2) use ($var1, $var2): bool {
// body
};
Списки аргументов и списки переменных МОГУТ быть разделены на несколько строк, при этом каждая последующая строка имеет один отступ. При этом первый элемент в списке ДОЛЖЕН находиться на следующей строке, и в каждой строке ДОЛЖЕН быть только один аргумент или переменная.
Когда конечный список (будь то аргументы или переменные) разбит на несколько строк, закрывающаяся и открывающая скобки ДОЛЖНЫ располагаться вместе на отдельной строке с одним пробелом между ними.
Ниже приведены примеры замыканий со списками аргументов и без них, а также списками переменных, разбитыми на несколько строк.
<?php
$longArgs_noVars = function (
$longArgument,
$longerArgument,
$muchLongerArgument,
) {
// body
};
$noArgs_longVars = function () use (
$longVar1,
$longerVar2,
$muchLongerVar3,
) {
// body
};
$longArgs_longVars = function (
$longArgument,
$longerArgument,
$muchLongerArgument,
) use (
$longVar1,
$longerVar2,
$muchLongerVar3
) {
// body
};
$longArgs_shortVars = function (
$longArgument,
$longerArgument,
$muchLongerArgument,
) use ($var1) {
// body
};
$shortArgs_longVars = function ($arg) use (
$longVar1,
$longerVar2,
$muchLongerVar3,
) {
// body
};
Обратите внимание, что правила форматирования также применяются, когда замыкание используется непосредственно в вызове функции или метода в качестве аргумента.
<?php
$foo->bar(
$arg1,
function ($arg2) use ($var1) {
// body
},
$arg3,
);
Короткие замыкание, так же известные как стрелочные функции, ДОЛЖНЫ следовать тем же правилам и принципам, что и длинные замыкания, описанные выше, со следующими дополнениями.
После ключевого слова fn НЕ ДОЛЖЕН ставиться пробел.
Символу => ДОЛЖЕН предшествовать и следовать за ним пробел.
Точке с запятой в конце выражения НЕ ДОЛЖЕН предшествовать пробел.
Часть выражения МОЖЕТ быть разделена на следующую строку. В этом случае знак => ДОЛЖЕН быть включен во вторую строку и ДОЛЖЕН иметь один отступ.
Следующие примеры показывают правильное использование коротких замыканий.
$func = fn(int $x, int $y): int => $x + $y;
$func = fn(int $x, int $y): int
=> $x + $y;
$func = fn(
int $x,
int $y,
): int
=> $x + $y;
$result = $collection->reduce(fn(int $x, int $y): int => $x + $y, 0);
Анонимные классы ДОЛЖНЫ следовать тем же правилам и принципам, что и замыкания в приведенном выше разделе.
<?php
$instance = new class {};
Открывающая скобка МОЖЕТ находиться в той же строке, что и ключевое слово класса, если список реализуемых интерфейсов не переносится. Если список интерфейсов переносится, то фигурная скобка ДОЛЖНА быть помещена в строку, следующую сразу за последним интерфейсом.
Если анонимный класс не имеет аргументов, символ () после класса ДОЛЖЕН быть опущен. Например:
<?php
// Brace on the same line
// No arguments
$instance = new class extends \Foo implements \HandleableInterface {
// Class content
};
// Brace on the next line
// Constructor arguments
$instance = new class($a) extends \Foo implements
\ArrayAccess,
\Countable,
\Serializable
{
public function __construct(public int $a)
{
}
// Class content
};
Перечисления (enums) ДОЛЖНЫ следовать тем же правилам, что и классы, если иное не указано ниже.
Методы в перечислениях ДОЛЖНЫ следовать тем же правилам, что и методы в классах. Непубличные методы ДОЛЖНЫ использовать private вместо protected, поскольку перечисления не поддерживают наследование.
При использовании типизированного перечисления НЕ ДОЛЖНО быть пробела между именем перечисления и двоеточием, а между двоеточием и типом ДОЛЖЕН быть ровно один пробел. Это соответствует стилю возвращаемых типов.
Объявления регистров перечислений ДОЛЖНЫ использовать заглавные буквы PascalCase. Объявления регистра перечисления ДОЛЖНЫ быть на отдельной строке.
Константы в перечислениях МОГУТ использовать заглавные буквы PascalCase или UPPER_CASE. РЕКОМЕНДУЕТСЯ использовать PascalCase, чтобы он соответствовал объявлениям регистров.
В следующем примере показан корректно отформатированный Enum:
enum Suit: string
{
case Hearts = 'H';
case Diamonds = 'D';
case Spades = 'S';
case Clubs = 'C';
const Wild = self::Spades;
}
Везде, где это возможно, СЛЕДУЕТ использовать документ nowdoc. Heredoc МОЖЕТ использоваться, когда nowdoc не удовлетворяет требованиям.
Синтаксис heredoc и nowdoc во многом регулируется требованиями PHP, единственным допустимым изменением является отступ. Объявленные heredoc или nowdocs ДОЛЖНЫ начинаться с той же строки, что и контекст, в котором используется объявление. Последующие строки в heredoc или nowdoc ДОЛЖНЫ иметь отступ после отступа области, в которой они объявлены.
Следующее недопустимо, поскольку heredoc начинается на строке, отличной от контекста, в котором он объявлен:
$notAllowed =
<<<'COUNTEREXAMPLE'
This
is
not
allowed.
COUNTEREXAMPLE;
Вместо этого heredoc ДОЛЖЕН быть объявлен в той же строке, что и объявление переменной, для которой он устанавливается.
Следующее не разрешено, поскольку отступ области не соответствует области, в которой объявлен heredoc:
function notAllowed()
{
$notAllowed = <<<'COUNTEREXAMPLE'
This
is
not
allowed.
COUNTEREXAMPLE
}
Вместо этого heredoc ДОЛЖЕН иметь отступ после отступа области, в которой он объявлен.
Ниже приведен пример heredoc и nowdoc, объявленных корректным образом:
function allowed()
{
$allowedHeredoc = <<<COMPLIANT
This
is
a
compliant
heredoc
COMPLIANT;
$allowedNowdoc = <<<'COMPLIANT'
This
is
a
compliant
nowdoc
COMPLIANT;
var_dump(
'foo',
<<<'COMPLIANT'
This
is
a
compliant
parameter
COMPLIANT,
'bar',
);
}
Массивы ДОЛЖНЫ быть объявлены с использованием короткого синтаксиса.
<?php
$arr = [];
Массивы ДОЛЖНЫ следовать правилам, которые описаны в разделе про запятые.
Объявления массива МОГУТ быть разделены на несколько строк, где каждая последующая строка имеет один отступ. При этом первое значение в массиве ДОЛЖНО находиться в следующей строке, и в каждой строке ДОЛЖНО быть только одно значение.
Когда объявление массива разбито на несколько строк, открывающая скобка ДОЛЖНА быть помещена в ту же строку, что и знак равенства. Закрывающую скобку ДОЛЖНО ставить на следующей строке после последнего значения. НЕ ДОЛЖНО быть более одного присвоения значения в строке. Присвоение значений МОГУТ использовать одну или несколько строк.
Следующий пример показывает правильное использование массива:
<?php
$arr1 = ['single', 'line', 'declaration'];
$arr2 = [
'multi',
'line',
'declaration',
['values' => 1, 5, 7],
[
'nested',
'array',
],
];
Имена атрибутов ДОЛЖНЫ следовать сразу за индикатором открывающего блока атрибутов #[ без пробела.
Если атрибут не имеет аргументов, символ () ДОЛЖЕН отсутствовать.
Индикатор закрывающего блока атрибутов ] ДОЛЖЕН следовать за последним символом имени атрибута или закрывающей скобкой ) его списка аргументов без предшествующего пробела.
Конструкция #[...] в этом документе называется «блоком атрибутов».
Атрибуты классов, методов, функций, констант и свойств ДОЛЖНЫ быть размещены на отдельной строке непосредственно перед описываемой структурой.
Для атрибутов параметров, если список параметров представлен в одной строке, атрибут ДОЛЖЕН быть помещен рядом с описываемым им параметром, разделенным одним пробелом. Если список параметров по какой-либо причине разбит на несколько строк, атрибут ДОЛЖЕН быть помещен в отдельную строку перед параметром с таким же отступом, как и параметр. Если список параметров разбит на несколько строк, для удобства чтения между одним параметром и атрибутами следующего параметра МОЖЕТ быть включена пустая строка.
Если аннотации с комментариями присутствуют в структуре, которая также включает атрибут, блок комментариев ДОЛЖЕН идти первым, за ним следуют любые атрибуты, а затем сама структура. Между аннотациями и атрибутами или атрибутами и структурой НЕ ДОЛЖНО быть пустых строк.
Если два отдельных блока атрибутов используются в многострочном контексте, они ДОЛЖНЫ находиться в отдельных строках без пустых строк между ними.
Если несколько атрибутов помещены в один и тот же блок атрибутов, они ДОЛЖНЫ быть разделены запятой с пробелом после него, но без пробела перед ним. Если список атрибутов по какой-либо причине разделен на несколько строк, атрибуты ДОЛЖНЫ быть помещены в отдельные блоки атрибутов. Эти блоки сами могут содержать несколько атрибутов при условии соблюдения этого правила.
Если список аргументов атрибута по какой-либо причине разбит на несколько строк, то:
Ниже приведен пример допустимого использования атрибутов.
#[Foo]
#[Bar('baz')]
class Demo
{
#[Beep]
private Foo $foo;
public function __construct(
#[Load(context: 'foo', bar: true)]
private readonly FooService $fooService,
#[LoadProxy(context: 'bar')]
private readonly BarService $barService,
) {}
/**
* Sets the foo.
*/
#[Poink('narf'), Narf('poink')]
public function setFoo(#[Beep] Foo $new): void
{
// ...
}
#[Complex(
prop: 'val',
other: 5,
)]
#[Other, Stuff]
#[Here]
public function complicated(
string $a,
#[Decl]
string $b,
#[Complex(
prop: 'val',
other: 5,
)]
string $c,
int $d,
): string {
// ...
}
}
Оригинал статьи тут: https://www.php-fig.org/per/coding-style/ - актуально на 30/10/2023
Ура! Я наконец-то дописал статью как собирать собственные бандлы на Symfony 6!!!
Статья про EasyAdmin всё ещё в процессе )))
Не, ну мне же надо на чем-то тестировать твиттер локальный...
Я тут еще много полезного буду выкладывать, так что заходите обязательно почитать.
Сайтик пока что в разработке - это далеко не окончательная версия - по сути это то что удалось слепить за 8 часов.
Комментарии