Перевод рекомендаций по стандартам PSR-1, PSR-4 и PSR-12

5 января 2017
Стандарты описывают подход к написанию программного кода. Этот стандарт получил наибольшее распространение, хотя некоторые его правила и рекомендации спорные. В проектах с участием нескольких разработчиков и где нет собственного набора правил по написанию когда, рекомендуется применять именно PSR.

В данной статье представлен сокращённый машинный перевод стандартов, взятых с официального сайта https://www.php-fig.org/

Оригинальная документация по PSR-1 (англ. яз): https://www.php-fig.org/psr/psr-1/
Оригинальная документация по PSR-4 (англ. яз): https://www.php-fig.org/psr/psr-4/
Оригинальная документация по PSR-12 (англ. яз): https://www.php-fig.org/psr/psr-12/

PSR-1: базовый стандарт написания кода

1. Обзор

  • Файлы ДОЛЖНЫ использовать только теги <?php и <?=
  • Файлы ДОЛЖНЫ использовать только UTF-8 без спецификации для PHP-кода.
  • Файлы ДОЛЖНЫ либо объявлять символы (классы, функции, константы и т.д.), либо вызывать побочные эффекты (например, генерировать выходные данные, изменять настройки .ini и т.д.), Но НЕ ДОЛЖНЫ выполнять и то, и другое.
  • Пространства имен и классы ДОЛЖНЫ соответствовать автозагрузке в соответствии с PSR-4.
  • Имена классов ДОЛЖНЫ быть объявлены в PascalCase.
  • Константы класса ДОЛЖНЫ быть объявлены в SCREAMING_SNAKE_CASE  (то есть полностью в верхнем регистре с разделителями подчеркивания).
  • Имена методов ДОЛЖНЫ быть объявлены в camelCase.

2. Файлы

2.1. Теги PHP
Код PHP ДОЛЖЕН использовать длинные <?php ?> теги или короткую версию <?= ?> он НЕ ДОЛЖЕН использовать другие варианты тегов.

2.2. Кодировка символов
PHP-код ДОЛЖЕН использовать только UTF-8 без меток порядка байтов (BOM, https://ru.wikipedia.org/wiki/Маркер_последовательности_байтов).

2.3. Побочные эффекты
Файл ДОЛЖЕН объявлять новые сущности (классы, функции, константы и т.д.) И не вызывать никаких других побочных эффектов, или он ДОЛЖЕН выполнять логику с побочными эффектами, но НЕ ДОЛЖЕН выполнять и то, и другое.

Фраза "побочные эффекты" означает выполнение логики, не связанной напрямую с объявлением классов, функций, констант и т.д., просто с включением файла.

"Побочные эффекты" включают, но не ограничиваются ими: генерация выходных данных, явное использование require или include, подключение к внешним службам, изменение настроек ini, выдача ошибок или исключений, изменение глобальных или статических переменных, чтение из файла или запись в файл и так далее.

Ниже приведен пример файла как с объявлениями, так и с побочными эффектами; т.е. Пример того, чего следует избегать:
<?php
// Побочный эффект. Изменения настройки error_reporting
ini_set('error_reporting', E_ALL);

// Побочный эффект. Подключение файла
include "file.php";

// Побочный эффект. Вывод тега
echo "<html>\n";

// Объявление функции
function foo()
{
    // тело функции
}

Ниже приведен пример файла, содержащего объявление сущностей без побочных эффектов, т. е. пример того, как нужно делать:
<?php
// Объявление функции
function foo()
{
    // Тело функции
}

// Объявление функции с предварительной проверкой существования функции не является побочный эффектом
if (! function_exists('bar')) {
    function bar()
    {
        // Тело функции
    }
}

3. Пространство имен и имена классов

Пространства имен и классы ДОЛЖНЫ соответствовать автозагрузке в соответствии с PSR-4.

Это означает, что каждый класс находится в отдельном файле и в пространстве имен по крайней мере одного уровня: имени поставщика верхнего уровня.

Имена классов ДОЛЖНЫ быть объявлены в PascalCase.

Код, написанный для PHP 5.3 и более поздних версий, должен использовать формальные пространства имен. Пример:
<?php
// PHP 5.3 и последующие версии
namespace Vendor\Model;

class Foo
{
}

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

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

4.1. Константы
Константы класса ДОЛЖНЫ быть объявлены в SCREAMING_SNAKE_CASE  (то есть полностью в верхнем регистре с разделителями подчеркивания). Например:
<?php
namespace Vendor\Model;

class Foo
{
    const VERSION = '1.0';
    const DATE_APPROVED = '2012-06-01';
}

4.2. Свойства
В этом руководстве намеренно избегаются какие-либо рекомендации относительно использования PascalCase, camelCase или snake_case для имен свойств.

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

4.3. Методы
Имена методов ДОЛЖНЫ быть объявлены в camelCase().


PSR-4: автозагрузчик

1. Общее

Этот PSR описывает спецификацию для автоматической загрузки классов из файловых путей. Он полностью совместим и может использоваться в дополнение к любой другой спецификации автоматической загрузки, включая PSR-0. Этот PSR также описывает, куда поместить файлы, которые будут автоматически загружены в соответствии со спецификацией.

2. Спецификация

1. Термин "класс" относится к классам, интерфейсам, признакам и другим подобным структурам.

2. Полное имя класса имеет следующий вид:
 \<NamespaceName>(\<SubNamespaceNames>)*\<ClassName>
  • Полное имя класса ДОЛЖНО содержать пространства имен верхнего уровня, также известное как "пространство имен поставщика".
  • Полное имя класса МОЖЕТ содержать одно или несколько вложенных пространств имен.
  • Полное имя класса ДОЛЖНО иметь завершающее имя класса.
  • Символы подчеркивания не имеют особого значения ни в одной части полного имени класса.
  • Буквенные символы в полном названии класса МОГУТ представлять собой любую комбинацию строчных и заглавных букв.
  • Все имена классов ДОЛЖНЫ упоминаться с учетом регистра.

3. При загрузке файла, соответствующего полному имени класса ...
  • Непрерывный ряд из одного или нескольких ведущих имен пространств имен и подпространств имен, не включая ведущий разделитель пространств имен, в полном квалифицированном имени класса ("префикс пространства имен") соответствует по крайней мере одному "базовому каталогу".
  • Смежные имена подпространств после "префикса пространства имен" соответствуют подкаталогу внутри "базового каталога", в котором разделители пространств имен представляют собой разделители каталогов. Имя подкаталога ДОЛЖНО соответствовать регистру имен подпространств имен.
  • Завершающее имя класса соответствует имени файла, заканчивающемуся на .php. Имя файла ДОЛЖНО соответствовать регистру имени завершающего класса.

4. Реализация автозагрузки НЕ ДОЛЖНА выбрасывать исключения, НЕ ДОЛЖНА вызывать ошибки любого уровня и НЕ ДОЛЖНА возвращать значение.

3. Примеры

В таблице ниже показан соответствующий путь к файлу для данного полного имени класса, префикса пространства имён и базового каталога.
 ПОЛНОЕ ИМЯ КЛАССА  ПРЕФИКС ПРОСТРАНСТВА ИМЁН  БАЗОВАЯ ДИРЕКТОРИЯ  ПУТЬ К КОНЕЧНОМУ ФАЙЛУ
 \Acme\Log\Writer\File_Writer  Acme\Log\Writer  ./acme-log-writer/lib/  ./acme-log-writer/lib/File_Writer.php
 \Aura\Web\Response\Status  Aura\Web  /path/to/aura-web/src/  /path/to/aura-web/src/Response/Status.php
 \Symfony\Core\Request  Symfony\Core  ./vendor/Symfony/Core/  ./vendor/Symfony/Core/Request.php
 \Zend\Acl  Zend  /usr/includes/Zend/  /usr/includes/Zend/Acl.php


PSR-12: расширенный стандарт написания кода

1. Общее

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

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

2. Общие сведения

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

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

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

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

2.3 Строки
Жесткого ограничения длины строки БЫТЬ НЕ должно.

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

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

В конце строк НЕ ДОЛЖНО быть завершающих пробелов.

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

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

2.4 Отступ
Код ДОЛЖЕН использовать отступ в 4 пробела для каждого уровня отступа и НЕ ДОЛЖЕН использовать табуляцию для отступа.

2.5 Ключевые слова и типы
Все зарезервированные PHP ключевые слова и типы ДОЛЖНЫ быть в нижнем регистре.

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

НЕОБХОДИМО использовать краткую форму ключевых слов типа, т.е. bool вместо boolean, int вместо integer и т.д.

3. Операторы ОБЪЯВЛЕНИЙ, Namespace и Import

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

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

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

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

Следующий пример иллюстрирует полный список всех блоков:
<?php

/**
 * This file contains an example of coding styles.
 */

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
{
    // ... additional PHP code ...
}

Составные пространства имен с глубиной более двух НЕ ДОЛЖНЫ использоваться. Ниже приведена максимально допустимая глубина объединения:
<?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(strict_types=1) (с необязательной точкой с запятой).

Блоки с объявлениями ДОЛЖНЫ быть отформатированы, как показано ниже. Обратите внимание на положение фигурных скобок и интервалов:
declare(ticks=1) {
    // some code
}

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

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

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

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

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

Перечень (список) implements, а в случае интерфейсов extends МОГУТ быть разделены на несколько строк, где каждая последующая строка имеет один отступ. Когда делать таким образом, первый элемент в списке должен быть на следующей строке, и там нужно быть только один интерфейс на линию.
<?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 Использование трейтов (trait)
Ключевое слово 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
<?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 Свойства и константы
Видимость ДОЛЖНА быть объявлена во всех свойствах.

Видимость ДОЛЖНА быть объявлена для всех констант, если минимальная версия PHP вашего проекта поддерживает постоянную видимость (для PHP 7.1 или более поздней версии).

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

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

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

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

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

namespace Vendor\Package;

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

4.4 Методы и функции
Видимость ДОЛЖНА быть объявлена для всех методов.

Имена методов НЕ ДОЛЖНЫ начинаться одним подчеркиванием для обозначения protected или private видимости. То есть префикс подчеркивания явно не имеет значения.

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

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

namespace Vendor\Package;

class ClassName
{
    public function fooBarBaz($arg1, &$arg2, $arg3 = [])
    {
        // method body
    }
}

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

function fooBarBaz($arg1, &$arg2, $arg3 = [])
{
    // function body
}

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

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

namespace Vendor\Package;

class ClassName
{
    public function foo(int $arg1, &$arg2, $arg3 = [])
    {
        // method body
    }
}

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

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

namespace Vendor\Package;

class ClassName
{
    public function aVeryLongMethodName(
        ClassTypeHint $arg1,
        &$arg2,
        array $arg3 = []
    ) {
        // method body
    }
}

Если у вас присутствует объявление возвращаемого типа, то после него ДОЛЖЕН быть один пробел и двоеточие, за которым следует объявление типа. Двоеточие и объявление ДОЛЖНЫ быть в той же строке, что и закрывающая скобка списка аргументов, без пробелов между двумя символами.
<?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';
    }
}

В объявлениях типов с нулевым значением, между вопросительным знаком и типом НЕ ДОЛЖНО быть пробела.
<?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 ДОЛЖНЫ предшествовать объявлению видимости.

Указание статичности через static ДОЛЖНО идти после объявления видимости.
<?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 ДОЛЖЕН быть один отступ от switch, а в ключевом слове break  (или других завершающих ключевых словах) ДОЛЖЕН быть отступ того же уровня, что и в теле case. Если в теле блока case нет управляющего слова break, ДОЛЖЕН быть добавлен комментарий вида // без прерывания через break  (для случая, когда провал/переход в другой case является намеренным)
<?php

switch ($expr) {
    case 0:
        echo 'First case, with a break';
        break;
    case 1:
        echo 'Second case, which falls through';
        // без прерывания через 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. Бинарные операторы
Все бинарные операторы арифметики, сравнения, присваивания, побитового, логического, строкового и типа ДОЛЖНЫ предшествовать и сопровождаться по крайней мере одним пробелом:
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, двоеточие ДОЛЖНО следовать за 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 {};

Открывающая фигурная скобка МОЖЕТ располагаться в той же строке, что и class ключевое слово, при условии, что список implements интерфейсов не завершается. Если список интерфейсов переносится, скобка ДОЛЖНА быть помещена в строку, следующую сразу за последней интерфейс.
<?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
};