Стандарт для разработчиков PHP (Bitrix)


Общие положения

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

Эта руководство по стилю кодирования расширяет PSR-12, с учетом стандарта оформления кода Bitrix.

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

Правила написания кода Битрикс

PSR-12: Extended Coding Style

Пример

Этот пример охватывает некоторые из приведенных ниже правил в качестве краткого обзора:

<?

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()
    {
        // method body
    }
}

2. Форматирование кода

2.1 Файлы

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

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

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

2.2 Длина строки и правила переноса

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

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

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

Необходимо пользоваться следующими правилами переноса:

  • переносить можно после запятой или перед оператором;
  • переносимая строка должна быть сдвинута относительно верхней на один символ табуляции;
  • переносы должны быть в стиле UNIX.

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

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

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

Пример 1: для строки

$arAuthResult = $USER->ChangePassword($USER_LOGIN, $USER_CHECKWORD, $USER_PASSWORD, $USER_CONFIRM_PASSWORD, $USER_LID);

допустимым будет следующий вариант переноса

$arAuthResult = $USER->ChangePassword($USER_LOGIN, $USER_CHECKWORD,
     $USER_PASSWORD, $USER_CONFIRM_PASSWORD, $USER_LID);

Пример 2: для строки

if(COption::GetOptionString("main", "new_user_registration", "N")=="Y" 
&& $_SERVER['REQUEST_METHOD']=='POST' && $TYPE=="REGISTRATION" && (!defined("ADMIN_SECTION") || ADMIN_SECTION!==true)) 

допустимым будет следующий вариант переноса

if (COption::GetOptionString("main", "new_user_registration", "N") == "Y"
    && $_SERVER['REQUEST_METHOD'] == 'POST' && $TYPE == "REGISTRATION"
    && (!defined("ADMIN_SECTION") || ADMIN_SECTION !== true))

2.3 Пробелы и табуляция

Для форматирования отступов в коде ДОЛЖНА использоваться табуляция. Использование пробелов запрещено. Причины:

  • в случае использования табуляции каждый может настроить в своем редакторе желаемый отступ;
  • используется один символ вместо нескольких;
  • в случае смешивания пробелов и табуляции текст будет прыгать, разрушая форматирование.

2.4 Форматирование подчиненности

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

Пример:

function func()
{
    if (condition)
    {
        while (condition2)
        {

        }
    }
}

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

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

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

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

2.6 Правила расстановки фигурных скобок

Открывающая скобка должна ставится под соответствующим оператором и на одном отступе с ним. Закрывающая скобка должна ставится под соответствующей открывающей.

Пример:

if ($condition)
{
    ...
}

2.7 Выражения

Желательно, чтобы в каждой строчке присутствовало только одно выражение.

Пример. Неправильно писать так:

$a = $b; $b = $c; $c = $a;

Правильно писать так

$a = $b;
$b = $c;
$c = $a;

2.8 Форматирование массивов

Массивы, которые записываются в несколько строк, следует форматировать следующим образом:

$arFilter = array(
    "key1" => "value1",
    "key2" => array(
        "key21" => "value21",
        "key22" => "value22",
    )
); 

2.9 Пустые строки и пробелы

Пустые строки

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

Перед логической секцией рекомендуется вставить комментарий, в котором будет указано назначение этой секции.

Пробелы

После запятой должен быть пробел. После точки с запятой, если она не последняя в строке (например, в инструкции for), должен быть пробел. Перед запятой или точкой с запятой пробелы не ставятся. Все операторы должны быть отделены пробелом от операндов с обеих сторон. Замена пробела символом табуляции не допускается.

Пояснения:

  • Один пробел используется в объявлении методов после запятой, но не перед скобками: TestMethod($a, $b, $c);

Примеры неправильного использования: TestMethod($a,$b,$c); TestMethod( $a, $b, $c );

  • Так же одиночный пробел используют для выделения операторов: $a = $b * $c / $d;

Пример неправильного использования: $a=$b*$c/$d; * Также пробелы используются при форматировании циклов: for ($i = 0; $i < 10; $i++).

Пример неправильного использования: for($i=0;$i<10;$i++)

  • Табуляция всегда используется для отступов, но никогда не используется вместо пробелов.

Пример неправильного форматирования (символ табуляции обозначен стрелкой):

$arArray = array(
    "key1" =>→"value1",
    "key2" =>→"value2",
    );

--Примечание: присутствие или отсутствие пробела после if правилами не регламентируется.--

В сложных выражениях рекомендуется группировать операции с помощью скобок вне зависимости от того, требует это приоритет операций или нет.

Пример: $r = $a + ($b * $c);>)>)

3. Оператор Declare, Namespace и операторы Import

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

  • Открытие тега <?.
  • Файловый doc-блок.
  • Один или несколько операторов declare.
  • Пространства имен файла.
  • Один или несколько импорт операторов use на основе классов.
  • Один или несколько импорт операторов use на основе функций.
  • Один или несколько use операторов import на основе констант.
  • Остальная часть кода в файле.

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

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

Операторы import НЕ ДОЛЖНЫ начинаться с обратной косой черты, поскольку они всегда должны быть полностью уточненный (qualified).

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

<?

/**
 * 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  code ...
}

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

<?

use Vendor\Package\SomeNamespace\{
    SubnamespaceOne\ClassA,
    SubnamespaceOne\ClassB,
    SubnamespaceTwo\ClassY,
    ClassZ,
};    

И не разрешено следующее:

<?

use Vendor\Package\SomeNamespace\{
    SubnamespaceOne\AnotherNamespace\ClassA,
    SubnamespaceOne\ClassB,
    ClassZ,
};    

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

Например:

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

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

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

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

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

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

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

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

new Foo();

4.1 Ключевые слова Extends и Implements

НЕОБХОДИМО, чтобы ключевые слова extends и implements были объявлены в той же строке, что и имя класса.

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

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

Закрывающие фигурные скобки ДОЛЖНЫ находиться на своей собственной строке и НЕ ДОЛЖНЫ предшествовать пустой строке.

<?

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 МОГУТ быть разбиты на несколько строк, где каждая последующая строка имеет один отступ. При этом первый элемент в списке ДОЛЖЕН быть на следующей строке, и ДОЛЖЕН быть только один интерфейс на строку.

<?

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 Использование трейтов (traits)

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

<?

namespace Vendor\Package;

use Vendor\Package\FirstTrait;

class ClassName
{
    use FirstTrait;
}    

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

<?

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.

<?

namespace Vendor\Package;

use Vendor\Package\FirstTrait;

class ClassName
{
    use FirstTrait;
}    

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

<?

namespace Vendor\Package;

use Vendor\Package\FirstTrait;

class ClassName
{
    use FirstTrait;

    private $property;
}    

При использовании операторов insteadof и as они должны использоваться следующим образом, принимая во внимание отступы, интервалы, и новые строки.

<?

class Talker
{
    use A, B, C {
        B::smallTalk insteadof A;
        A::bigTalk insteadof C;
        C::mediumTalk as FooBar;
    }
}    

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

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

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

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

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

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

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

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

<?

namespace Vendor\Package;

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

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

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

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

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

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

<?

namespace Vendor\Package;

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

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

<?

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

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

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

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

<?

namespace Vendor\Package;

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

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

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

<?

namespace Vendor\Package;

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

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

<?

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

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

<?

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
}    

При комбинировании оператора ссылки и оператора троеточия variadic, между ними не должно быть пространства:

public function process(string $algorithm, &...$parts)
{
    // processing
}    

4.6 abstract, final и static

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

Когда присутствует объявление static, оно ДОЛЖНО быть после объявления видимости.

<?

namespace Vendor\Package;

abstract class ClassName
{
    protected static $foo;

    abstract protected function zim();

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

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

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

<?

bar();
$foo->bar($arg1);
Foo::bar($arg2, $arg3);

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

<?

$foo->bar(
    $longArgument,
    $longerArgument,
    $muchLongerArgument
);    

<?

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 находятся на той же строке, что и закрывающая скобка из предыдущего тела.

Тело инструкции должно быть сдвинуто на один символ табуляции вправо от самой инструкции. Фигурные скобки должны использоваться всегда, находиться на отдельных строках, на одном уровне с инструкцией.

<?

if ($expr1) {
    // if body
} elseif ($expr2) {
    // elseif body
} else {
    // else body;
}    

Ключевое слово elseif ДОЛЖНО использоваться вместо else, если все контрольные ключевые слова выглядят как отдельные слова.

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

<?

if (
        $expr1
        && $expr2
   ) {
    // if body
} elseif (
        $expr3
        && $expr4
        ) {
    // elseif body
}    

5.2 switch, case

Структура switch выглядит следующим образом. Обратите внимание на расположение скобок, пробелов и фигурных скобок. Оператор case ДОЛЖЕН отделяться от switch одним отступом, а ключевое слово break (или другие завершающие ключевые слова) ДОЛЖНО иметь отступ на том же уровне, что и тело case. ДОЛЖЕН быть комментарий, такой как // no break, когда fall-through является преднамеренным в непустом теле case.

<?

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

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

<?

switch (
        $expr1
        && $expr2
       ) {
    // structure body
}    

5.3 while, do while

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

<?

while ($expr) {
    // structure body
}    

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

<?

while (
        $expr1
        && $expr2
      ) {
    // structure body
}    

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

<?

do {
    // structure body;
} while ($expr);    

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

<?

do {
    // structure body;
} while (
    $expr1
    && $expr2
);    

5.4 for

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

<?

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

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

<?

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

5.5 foreach

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

<?

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

5.6 try, catch, finally

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

<?

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. Тернарные (условные) операторы

Условный оператор ДОЛЖЕН начинаться и заканчиваться пробелом вокруг обоих ? и : символов.

Условие следует заключать в скобки, тем самым отделяя его от остального кода. По возможности, действия, производимые по условию, должны быть простыми функциями.

Если весь блок ветвления плохо читается, то стоит заменить его на if/else.

Пример:

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

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

$variable = $foo ?: ‘bar’;

7. Замыкания

Замыкания ДОЛЖНЫ быть объявлены с пробелом после ключевого слова function и пробелом до и после ключевого слова use.

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

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

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

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

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

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

<?

$closureWithArgs = function ($arg1, $arg2) {
    // body
};

$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {
    // body
};

$closureWithArgsVarsAndReturn = function ($arg1, $arg2) use ($var1, $var2): bool {
    // body
};    

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

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

Ниже приведены примеры замыканий со списками аргументов и без них, а также списков переменных, разделенных на несколько строк.

<?

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

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

<?

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

9. Соглашение об именовании

9.1. Общие понятия

Не используйте подчеркивание для отделения слов внутри идентификаторов, это удлиняет идентификаторы и затрудняет чтение.

Старайтесь давать переменным, методам и пр. "говорящие" названия. Предпочтительно использовать имена, которые ясно и четко описывают предназначение и/или смысл сущности.

Старайтесь делать имена идентификаторов как можно короче (но не в ущерб читабельности).

Если в имени содержится аббревиатура, лучше вместо всех заглавных оставить только первую букву заглавной, а остальные написать строчными. Т.е. лучше задать имя getHtmlStatistic, а не getHTMLStatistic.

9.2. Именование переменных

Первое логическое слово должно начинаться с маленькой буквы, остальные логические слова - с большой. Имена переменных могут иметь префиксы, если требуется явно указать тип переменной: ar - для массивов, db - для наборов данных из базы и т.п.

Пример: $testCounter, $userPassword.

9.3. Именование методов

  • Очевидность из названия действия, которое будет совершать функция\метод.
  • Использование префиксов: is (обозначение вопроса), get (получить значение), set (установить значение).

Пример: isFileWriteable()

9.4. Именование классов

  • В имени должна обозначаться сущность, описываемая классом.
  • В имени должно быть не более трех слов.
  • Нельзя использовать знак подчеркивания ('_').
  • В качестве разделителей слов в имени следует использовать заглавные буквы, строчные - для остальной части.

Пример: class SaleAffiliateAccount

10. Комментарии

Комментарий должны быть на английском языке и носить содержательный характер.

10.1. PHPDoc

Необходимо описывать в стиле PHPDoc все классы и их публичные методы.

Пример:

/**
* Gets a value that indicates whether a directory exists in the file system
*
* @param string $path - Path to the directory
* @return bool - True if the directory exists, false - otherwise
*/