Коротко: PSR-12 — стандарт оформления PHP-кода от PHP-FIG, расширяющий PSR-1; статья представляет собой перевод стандарта на русский.

PSR-12 — стандарт оформления PHP-кода от PHP-FIG, расширяющий PSR-1 и задающий единые правила форматирования. Ниже приведён перевод стандарта на русский. Это справочный материал, приведённый близко к оригиналу.

Приветствую, друзья!

Данная статья является переводом с официальной страницы стандарта PSR-12 по стилям написания кода на языке PHP. Ссылку на оригинал статьи вы сможете найти в самом низу статьи. Приятного чтения!

Ключевые слова «ДОЛЖЕН», «НЕ ДОЛЖЕН», «ТРЕБУЕТСЯ», «СЛЕДУЕТ», «НЕ СЛЕДУЕТ», «РЕКОМЕНДУЕТСЯ», «МОЖЕТ» и «ВОЗМОЖНО» в этом документе: интерпретироваться, как описано в RFC 2119.

Общее

Эта спецификация расширяет и заменяет PSR-2, руководство по стилю кодирования, и требует соблюдения PSR-1, основного стандарта кодирования.

Как и PSR-2, цель этой спецификации — уменьшить когнитивные трудности при проверке кода разных авторов. Это делается путем перечисления общего набора правил и ожиданий относительно форматирования кода на языке PHP. Этот PSR стремится предоставить набор правил, которые инструменты соблюдения стиля написания кода могут использовать, которыми можно декларировать проекты, к которым разработчики могут легко апеллировать и при взаимодействии между различными проектами. Когда разные авторы сотрудничают в нескольких проектах, полезно иметь один набор рекомендаций, который можно использовать во всех этих проектах. Таким образом, преимущество этого руководства заключается не в самих правилах, а в их распространении.

PSR-2 был принят в 2012 году, и с тех пор в PHP был внесен ряд изменений, которые влияют на рекомендации по стилю написания кода. Несмотря на то, что PSR-2 очень обширен из функциональных возможностей PHP, существовавших на момент написания, новые функциональные возможности очень открыты для интерпретации. Таким образом, данный PSR призван прояснить содержание PSR-2 в более современном контексте с доступными новыми функциями и внести исправления в привязку PSR-2.

Предыдущие версии языков

В этом документе любые инструкции МОГУТ быть проигнорированы, если они не существуют в версиях 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()
    {
        // тело метода
    }
}

2. Основы

2.1 Базовый стандарт написания кода

Код ДОЛЖЕН соответствовать всем правилам, изложенным в PSR-1.

Термин «StudlyCaps» в PSR-1 ДОЛЖЕН интерпретироваться как PascalCase, где первая буква каждого слова пишется с заглавной буквы, включая самую первую букву.

2.2 Файлы

Все файлы PHP ДОЛЖНЫ использовать только окончание строки Unix LF (перевод строки).

Все файлы PHP ДОЛЖНЫ заканчиваться непустой строкой, заканчивающейся одним LF.

Закрывающий тег ?> ДОЛЖЕН быть опущен в файлах, содержащих только PHP.

2.3 Строки

НЕ ДОЛЖНО быть жесткого ограничения на длину строки.

Мягкое ограничение длины строки ДОЛЖНО составлять 120 символов.

Строкам НЕ СЛЕДУЕТ быть длиннее 80 символов; строки длиннее этого СЛЕДУЕТ разбивать на несколько последующих строк длиной не более 80 символов каждая.

В конце строк НЕ ДОЛЖНО быть пробелов.

Пустые строки МОГУТ быть добавлены для улучшения читаемости и обозначения связанных блоков кода, за исключением случаев, когда это явно запрещено.

НЕ ДОЛЖНО быть более одной инструкции в строке. ( Под инструкцией имеется в виду например такое выражение $a = $b + $c; или любая другая инструкция заканчивающаяся символом ; )

2.4 Отступы

Код ДОЛЖЕН использовать отступ в 4 пробела для каждого уровня отступа и НЕ ДОЛЖЕН использовать для отступов табуляцию. ( 1 табуляция в IDE должна быть настроена именно как 4 пробельных символа, а не 1 таб-сдвиг )

2.5 Ключевые слова и типы

Все зарезервированные ключевые слова и типы в PHP [1][2] должны быть в нижнем регистре.

Любые новые типы и ключевые слова, добавленные в будущие версии PHP, ДОЛЖНЫ быть написаны в нижнием регистре.

Короткая форма ключевых слов ДОЛЖНА использоваться, например bool вместо boolean, int вместо integer и т.д.

3. Операторы declare, namespaces, и операторы import

Заголовок файла PHP может состоять из нескольких разных блоков. Если они присутствуют, каждый из приведенных ниже блоков ДОЛЖЕН быть разделен одной пустой строкой и НЕ ДОЛЖЕН содержать пустую строку. Каждый блок ДОЛЖЕН располагаться в порядке, указанном ниже, хотя ненужные блоки могут быть опущены.

  • Открывающий тег <?php.
  • Блок аннотаций уровня файла.
  • Один или несколько операторов declare.
  • Объявление пространства имен файла.
  • Один или несколько операторов импорта использования на основе классов.
  • Один или несколько операторов импорта использования на основе функций.
  • Один или несколько операторов импорта использования на основе констант.
  • Остальная часть кода в файле.

Если файл содержит смесь 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 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\{
    SubnamespaceOne\AnotherNamespace\ClassA,
    SubnamespaceOne\ClassB,
    ClassZ,
};

При желании объявить строгие типы в файлах, содержащих разметку вне открывающих и закрывающих тегов PHP, объявление ДОЛЖНО находиться в первой строке файла и включать открывающий тег PHP, объявление строгих типов и закрывающий тег.

Например:

<?php declare(strict_types=1) ?>
<html>
<body>
    <?php
        // ... additional PHP code ...
    ?>
</body>
</html>

Операторы declare НЕ ДОЛЖНЫ содержать пробелов и ДОЛЖНЫ быть точно объявлены следующим образом: declare(strict_types=1) (с необязательным разделителем-точкой с запятой).

Операторы declare ДОЛЖНЫ быть отформатированы, как показано ниже. Обратите внимание на положение скобок и пробелов:

declare(ticks=1) {
    // some code
}

4. Классы, свойства, и методы

Термин «класс» относится ко всем классам, интерфейсам и характеристикам.

За закрывающей скобкой НЕ ДОЛЖЕН следовать какой-либо комментарий или утверждение в той же строке.

При создании экземпляра нового класса круглые скобки ДОЛЖНЫ присутствовать всегда, даже если в конструктор не переданы аргументы.

new Foo();

4.1 Ключевые слова 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
}

4.2 Использование трейтов

Ключевое слово use, используемое внутри класса для подключения трейта ДОЛЖНО быть расположено на строке, следующей за открывающей скобкой.

<?php

namespace Vendor\Package;

use Vendor\Package\FirstTrait;

class ClassName
{
    use FirstTrait;
}

Каждый отдельный трейт, импортируемый в класс, ДОЛЖЕН быть подключаться по одному в строке, и каждое подключение ДОЛЖНО иметь свой собственный оператор 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 import.

<?php

namespace Vendor\Package;

use Vendor\Package\FirstTrait;

class ClassName
{
    use FirstTrait;
}

В противном случае ДОЛЖНА быть пустая строка после оператора use.

<?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;
    }
}

4.3 Свойства и константы

Область видимости ДОЛЖНА быть объявлена у всех свойств.

Область видимости ДОЛЖНА быть объявлена у всех константа в случае, если ваш продукт написан на версии PHP7.1 и выше.

Ключевое слово var НЕ ДОЛЖНО использоваться для объявления свойств.

На одной строке не должно быть объявлено более одного свойства.

Имена свойств НЕ ДОЛЖНЫ начинаться с одного подчеркивания, чтобы указать на защищенную или приватную область видимости. То есть префикс подчеркивания явно не имеет значения.

Между объявлением типа и именем свойства ДОЛЖЕН быть пробел.

Объявление свойства выглядит следующим образом:

<?php

namespace Vendor\Package;

class ClassName
{
    public $foo = null;
    public static int $bar = 0;
}

4.4 Методы и функции

Область видимости ДОЛЖНА быть объявлена для всех методов.

Имена методов НЕ ДОЛЖНЫ начинаться с одного подчеркивания, чтобы указать на защищенную или приватную область видимости. То есть префикс подчеркивания явно не имеет значения.

Имена методов и функций НЕ ДОЛЖНЫ объявляться с пробелом после имени метода. Открывающая скобка ДОЛЖНА идти на отдельной строке, а закрывающая скобка ДОЛЖНА идти на следующую строку после тела. НЕ ДОЛЖНО быть пробела после открывающей скобки и НЕ ДОЛЖНО быть пробела перед закрывающей скобкой.

Объявление метода выглядит следующим образом. Обратите внимание на размещение круглых скобок, запятых, пробелов и фигурных скобок:

<?php

namespace Vendor\Package;

class ClassName
{
    public function fooBarBaz($arg1, &$arg2, $arg3 = [])
    {
        // тело метода
    }
}

Объявление функции выглядит следующим образом. Обратите внимание на размещение круглых скобок, запятых, пробелов и фигурных скобок:

<?php

function fooBarBaz($arg1, &$arg2, $arg3 = [])
{
    // тело функции
}

4.5 Аргументы методов и функций

В списке аргументов НЕ ДОЛЖНО быть пробела перед каждой запятой и ДОЛЖЕН быть один пробел после каждой запятой.

Аргументы метода и функции со значениями по умолчанию ДОЛЖНЫ располагаться в конце списка аргументов.

<?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
}

4.6 Ключевые слова abstract, final, и static

Если они присутствуют, ключевые слова abstract и final ДОЛЖНЫ предшествовать объявлению области видимости.

Статическое объявление, если оно присутствует, ДОЛЖНО идти после объявления видимости.

<?php

namespace Vendor\Package;

abstract class ClassName
{
    protected static $foo;

    abstract protected function zim();

    final public static function bar()
    {
        // method body
    }
}

4.7 Вызовы методов и функций

При вызове метода или функции НЕ ДОЛЖНО быть пробела между именем метода или функции и открывающей скобкой, НЕ ДОЛЖНО быть пробела после открывающей скобки и НЕ ДОЛЖНО быть пробела перед закрывающей круглой скобкой. В списке аргументов НЕ ДОЛЖНО быть пробела перед каждой запятой и ДОЛЖЕН быть один пробел после каждой запятой.

<?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);
});

5. Управляющие структуры

Общие правила стиля управляющих структур следующие:

  • После ключевого слова управляющей структуры ДОЛЖЕН быть один пробел.
  • После открывающей скобки НЕ ДОЛЖНО быть пробела.
  • Перед закрывающей скобкой НЕ ДОЛЖНО быть пробела.
  • Между закрывающей скобкой и открывающей скобкой ДОЛЖЕН быть один пробел.
  • Тело структуры ДОЛЖНО иметь один отступ ( табуляцию )
  • Тело структуры ДОЛЖНО находиться на следующей строке после открывающей скобки.
  • Закрывающая скобка ДОЛЖНА находиться на следующей строке после тела

Тело каждой структуры ДОЛЖНО быть заключено в фигурные скобки. Это стандартизирует внешний вид структур и снижает вероятность появления ошибок при добавлении новых строк в тело.

5.1 Управляющие структуры if, elseif, else

Структура 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
}

5.2 Управляющие структуры switch, case

Структура 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
}

5.3 Управляющие структуры while, do while

Оператор 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
);

5.4 Управляющая структура for

Оператор for выглядит следующим образом. Обратите внимание на размещение круглых скобок, пробелов и фигурных скобок.

<?php

for ($i = 0; $i < 10; $i++) {
    // for body
}

Выражения в круглых скобках МОГУТ быть разделены на несколько строк, при этом каждая последующая строка имеет отступ хотя бы один раз. При этом первое выражение ДОЛЖНО находиться на следующей строке. Закрывающая и открывающая скобки ДОЛЖНЫ располагаться вместе на отдельной строке с одним пробелом между ними.

<?php

for (
    $i = 0;
    $i < 10;
    $i++
) {
    // for body
}

5.5 Управляющая структура foreach

Оператор foreach выглядит следующим образом. Обратите внимание на размещение круглых скобок, пробелов и фигурных скобок.

<?php

foreach ($iterable as $key => $value) {
    // foreach body
}

5.6 Управляющие структуры try, catch, finally

Блок try-catch-finally выглядит следующим образом. Обратите внимание на размещение круглых скобок, пробелов и фигурных скобок.

<?php

try {
    // try body
} catch (FirstThrowableType $e) {
    // catch body
} catch (OtherThrowableType | AnotherThrowableType $e) {
    // catch body
} finally {
    // finally body
}

6. Операторы

Правила стиля для операторов сгруппированы по арности (количеству принимаемых ими операндов).

Если вокруг оператора разрешены пробелы, то для удобства чтения МОГУТ использоваться несколько пробелов.

Все операторы, не описанные здесь, могут быть стилизованы на ваше усмотрение.

6.1 Унарные операторы

Операторы инкремента/декремента НЕ ДОЛЖНЫ иметь пробела между оператором и операндом.

$i++;
++$j;

Операторы приведения типов НЕ ДОЛЖНЫ иметь пробелов в круглых скобках:

$intValue = (int) $input;

6.2 Бинарные операторы

У всех бинарных arithmetic, comparison, assignment, bitwise, logical, string, и type операторов спереди и сзади ДОЛЖЕН быть хотя бы один пробел:

if ($a === $b) {
    $foo = $bar ?? $a ?? $b;
} elseif ($a > $b) {
    $foo = $a + $b * $c;
}

6.3 Тернарные операторы

В условном операторе, также известном как тернарный оператор, перед и после символов ? и : должен быть как минимум один пробел:

$variable = $foo ? 'foo' : 'bar';

Если средний операнд условного оператора отсутствует, оператор ДОЛЖЕН следовать тем же правилам стиля, что и другие операторы двоичного сравнения:

$variable = $foo ?: 'bar';

7. Замыкания

Замыкания ДОЛЖНЫ быть объявлены с пробелом после ключевого слова 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
);

8. Анонимные классы

Анонимные классы ДОЛЖНЫ следовать тем же правилам и принципам, что и замыкания в приведенном выше разделе.

<?php

$instance = new class {};

Открывающая скобка МОЖЕТ находиться в той же строке, что и ключевое слово класса, если список реализуемых интерфейсов не переносится. Если список интерфейсов переносится, то фигурная скобка ДОЛЖНА быть помещена в строку, следующую сразу за последним интерфейсом.

<?php

// Brace on the same line
$instance = new class extends \Foo implements \HandleableInterface {
    // Class content
};

// Brace on the next line
$instance = new class extends \Foo implements
    \ArrayAccess,
    \Countable,
    \Serializable
{
    // Class content
};

Оригинал статьи тут: https://www.php-fig.org/psr/psr-12/ - актуально на 29/10/2023