Оформлення основного коду фреймворку Yii 2

Нижченаведений стиль кодування використовується у розробці основного коду Yii 2.x та офіційних розширень. Дотримуйтесь його, якщо хочете вносити зміни в основний код. Команда розробників не наполягає на використанні цього стилю для вашого додатка. Вільно обирайте те, що підходить вам більше.

Ви можете отримати конфігурацію для CodeSniffer за посиланням: https://github.com/yiisoft/yii2-coding-standards

1. Загальні положення

В основному командою розробників використовується стиль сумісний з PSR-2, тому все, що стосується PSR-2, застосовується також.

  • У файлах НЕОБХІДНО використовувати теги або <?php або <?=.
  • Пустий рядок у кінці файлу є необхідним.
  • Файли з кодом PHP ПОВИННІ зберігатись лише у кодуванні UTF-8 без BOM.
  • Для кожного рівня відступу НЕОБХІДНО використовувати 4 пробіли, а не табуляцію.
  • Імена класів ПОВИННІ оголошуватись як StudlyCaps.
  • Імена констант класу ПОВИННІ оголошуватись повністю у верхньому регістрі, підкреслення використовується як роздільник.
  • Імена методів ПОВИННІ оголошуватись як camelCase.
  • Імена властивостей ПОВИННІ оголошуватись як camelCase.
  • Імена приватних властивостей ПОВИННІ починатись з підкреслення.
  • Завжди використовуйте elseif замість else if.

2. Файли

2.1. Теги PHP

  • PHP код ПОВИНЕН використовувати теги <?php ?> або <?=; він НЕ ПОВИНЕН використовувати інші варіації, такі як <?.
  • Якщо файл містить лише PHP він не повинен закінчуватись тегом ?>.
  • Не додавайте пробіли у кінці рядку.
  • Будь-який файл, який містить код PHP, повинен мати розширення .php.

2.2. Кодування символів

PHP код ПОВИНЕН використовувати лише UTF-8 без BOM.

3. Імена класів

Імена класів ПОВИННІ оголошуватись як StudlyCaps. Наприклад: Controller, Model.

4. Класи

Тут термін "клас" відноситься до всіх класів та інтерфейсів.

  • Класи повинні іменуватись як CamelCase.
  • Початкова фігурна дужка повинна завжди розміщуватись на наступному рядку після імені класу.
  • Кожний клас повинен мати блок документації, який відповідає стандарту PHPDoc.
  • Код всередині класу повинен бути зміщений на рівень відступу.
  • Один PHP файл може містити лише один клас.
  • Кожний клас повинен бути у просторі імен.
  • Ім’я класу повинне відповідати імені файлу. Простір імен класу повинен відповідати структурі директорій.
/**
 * Документація
 */
class MyClass extends \yii\Object implements MyInterface
{
    // код
}

4.1. Константи

Імена констант ПОВИННІ оголошуватись повністю у верхньому регістрі, підкреслення використовується як роздільник. Наприклад:

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

4.2. Властивості

  • При оголошенні публічних членів класу обов’язково вказуйте ключове слово public.
  • Публічні та захищені змінні повинні бути оголошенні у початку класу перед будь-яким оголошенням методу. Приватні змінні також повинні бути оголошенні у початку класу, але можуть бути вставленні безпосередньо перед методами, що ними оперують, у випадках коли змінні пов’язані лише з невеликою кількістю методів класу.
  • Порядок оголошення властивостей у класі повинен бути таким: спочатку публічні, потім захищені, а потім приватні.
  • Для кращої читабельності не повинно бути пустих рядків між оголошеннями властивостей та повинно бути два пустих рядки між секціями оголошення властивості та методу.
  • Приватні змінні повинні іменуватись як $_varName.
  • Публічні члени класу та автономні змінні повинні іменуватись як $camelCase (перша літера у нижньому регістрі).
  • Використовуйте описові імена. Змінні, такі як $i та $j, краще не використовувати.

Наприклад:

<?php
class Foo
{
    public $publicProp;
    protected $protectedProp;
    private $_privateProp;
}

4.3. Методи

  • Функції та методи повинні іменуватись як camelCase (перша літера у нижньому регістрі).
  • Ім’я повинне бути само-описовим та вказувати призначення функції.
  • Методи класу завжди повинні оголошувати видимість, використовуючи модифікатори private, protected та public. Не допускається використання var.
  • Початкова фігурна дужка функції повинна розміщуватись на наступному рядку після оголошення функції.
/**
 * Документація
 */
class Foo
{
    /**
     * Документація
     */
    public function bar()
    {
        // код
        return $value;
    }
}

4.4 Блоки документації PHPDoc (Doc-блоки)

@param, @var, @property та @return повинні оголошувати типи як boolean, integer, string, array чи null. Також можна використовувати імена класів, як наприклад: Model або ActiveRecord. Для типізованих масивів використовуйте ClassName[].

4.5 Конструктори

  • потрібно використовувати __construct замість стилю конструкторів PHP 4.

5 PHP

5.1 Типи

  • Усі типи PHP та значення повинні бути у нижньому регістрі. Це включає true, false, null та array.

Зміна типу змінної, що вже існує, вважається поганою практикою. Намагайтесь не писати такий код, поки в цьому дійсно нема потреби.

public function save(Transaction $transaction, $argument2 = 100)
{
    $transaction = new Connection; // погано
    $argument2 = 200; // добре
}

5.2 Текстові рядки

  • Якщо текстовий рядок не містить змінних чи одинарних лапок, використовуйте одинарні лапки.
$str = 'Текстовий рядок.';
  • Якщо текстовий рядок містить одинарні лапки, можна використовувати подвійні лапки, щоб уникнути додаткового екранування символів.

Підставлення змінної

$str1 = "Привіт, $username!";
$str2 = "Привіт, {$username}!";

Нижченаведений приклад не допускається:

$str3 = "Привіт, ${username}!";

Конкатенація

Додавайте пробіли навколо оператора конкатенації (.), коли об’єднуєте текстові рядки:

$name = 'Фреймворк ' . 'Yii';

Для довгих текстових рядків використовуйте наступний формат:

$sql = "SELECT *"
    . "FROM `post` "
    . "WHERE `id` = 121 ";

5.3 Масиви

Для масивів використовуйте скорочений синтаксис (PHP 5.4).

Індексовані масиви

  • Не використовуйте від’ємні числа для індексів масиву.

Використовуйте нижченаведений формат оголошення масиву:

$arr = [3, 14, 15, 'Yii', 'фреймворк'];

Якщо забагато елементів для одного рядка:

$arr = [
    3, 14, 15,
    92, 6, $test,
    'Yii', 'фреймворк',
];

Асоціативні масиви

Використовуйте нижченаведений формат для асоціативних масивів:

$config = [
    'name'  => 'Yii',
    'options' => ['usePHP' => true],
];

5.4 Керування порядком виконання

  • Перед умовою керувальної інструкції та після неї повинен бути пробіл.
  • Оператори всередині круглих дужок повинні відокремлюватись пробілами.
  • Початкова фігурна дужка розміщена на тому самому рядку.
  • Кінцева фігурна дужка розміщена на новому рядку.
  • Завжди використовуйте фігурні дужки для конструкцій з одного рядка.
if ($event === null) {
    return new Event();
}
if ($event instanceof CoolEvent) {
    return $event->instance();
}
return null;


// нижченаведений приклад НЕ допускається:
if (!$model && null === $event)
    throw new Exception('test');

Краще уникайте використання else після return, де це має сенс. Використовуйте вартові умови.

$result = $this->getResult();
if (empty($result)) {
  return true;
} else {
  // обробка результату
}

буде краще так:

$result = $this->getResult();
if (empty($result)) {
  return true;
}

// обробка результату

switch

Використовуйте наступний формат для switch:

switch ($this->phpType) {
    case 'string':
        $a = (string) $value;
        break;
    case 'integer':
    case 'int':
        $a = (int) $value;
        break;
    case 'boolean':
        $a = (bool) $value;
        break;
    default:
        $a = null;
}

5.5 Виклики функції

doIt(2, 3);

doIt(['a' => 'b']);

doIt('a', [
    'a' => 'b',
    'c' => 'd',
]);

5.6 Оголошення анонімних (лямбда) функцій

Зверніть увагу на пробіл між function/use та початковою круглою дужкою:

// добре
$n = 100;
$sum = array_reduce($numbers, function ($r, $x) use ($n) {
    $this->doMagic();
    $r += $x * $n;
    return $r;
});

// погано
$n = 100;
$mul = array_reduce($numbers, function($r, $x) use($n) {
    $this->doMagic();
    $r *= $x * $n;
    return $r;
});

Документація

  • Див. PHPDoc для довідки про синтаксис документації.
  • Код без документації не допускається.
  • Усі файли класів повинні містити файловий ("file-level") doc-блок на початку та класовий ("class-level") doc-блок безпосередньо над кожним класом.
  • Нема потреби використовувати @return, якщо метод нічого не повертає.
  • Усі віртуальні властивості у класах успадкованих від yii\base\Object документуються з тегом @property у класовому doc-блоці. Ці анотації генеруються автоматично із тегів @return чи @param відповідних геттерів або сеттерів виконанням команди ./build php-doc у директорії build. Ви можете додати тег @property до геттеру або сеттеру, щоб точно визначити повідомлення для документації властивості, яка представляється цими методами, коли опис відрізняється від того, що встановлено тегом @return. Наприклад:

php <?php /** * Returns the errors for all attributes or a single attribute. * @param string $attribute attribute name. Use null to retrieve errors for all attributes. * @property array An array of errors for all attributes. Empty array is returned if no error. * The result is a two-dimensional array. See [[getErrors()]] for detailed description. * @return array errors for all attributes or the specified attribute. Empty array is returned if no error. * Note that when returning errors for all attributes, the result is a two-dimensional array, like the following: * ... */ public function getErrors($attribute = null)

Файл

<?php
/**
 * @link http://www.yiiframework.com/
 * @copyright Copyright (c) 2008 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

Клас

/**
 * Component is the base class that provides the *property*, *event* and *behavior* features.
 *
 * @include @yii/docs/base-Component.md
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
class Component extends \yii\base\Object

Функція / метод

/**
 * Returns the list of attached event handlers for an event.
 * You may manipulate the returned [[Vector]] object by adding or removing handlers.
 * For example,
 *
 * ~~~
 * $component->getEventHandlers($eventName)->insertAt(0, $eventHandler);
 * ~~~
 *
 * @param string $name the event name
 * @return Vector list of attached event handlers for the event
 * @throws Exception if the event is not defined
 */
public function getEventHandlers($name)
{
    if (!isset($this->_e[$name])) {
        $this->_e[$name] = new Vector;
    }
    $this->ensureBehaviors();
    return $this->_e[$name];
}

Markdown

Як ви могли побачити у прикладах вище, для форматування коментарів PHPDoc використовується markdown.

Існує додатковий синтаксис для створення перехресних посилань між класами, методами та властивостями у документації:

  • '[[canSetProperty]] створить посилання на метод або властивість canSetProperty того ж самого класу.
  • '[[Component::canSetProperty]] створить посилання на метод canSetProperty класу Component в тому ж самому просторі імен.
  • '[[yii\base\Component::canSetProperty]] створить посилання на метод canSetProperty класу Component з простору імен yii\base.
  • '[[Component]] створить посилання на клас Component в тому ж самому просторі імен. Додавання простору імен до імені класу тут також можливе.

Щоб для одного з вище зазначених посилань вказати мітку відмінну від імені класу чи методу, ви можете використовувати синтаксис, показаний в нижченаведеному прикладі:

... as displayed in the [[header|header cell]].

Частина перед | є найменуванням методу, властивості або класу, в той час як частина після | є міткою посилання.

Також можливо посилатись на Посібник, використовуючи наступний синтаксис:

[link to guide](guide:file-name.md)
[link to guide](guide:file-name.md#subsection)

Коментарі

  • Одно-рядкові коментарі повинні починатись з //, а не з #.
  • Одно-рядковий коментар повинен бути розміщений на власному рядку.

Додаткові правила

=== [] проти empty()

Використовуйте empty(), де можливо.

Кілька інструкцій return

При великій вкладеності умов, використовуйте інструкцію return раніше. Якщо метод не великий, це неважливо.

self проти static

Завжди використовуйте static, за виключенням наведених випадків:

  • отримання значень констант ПОВИННО виконуватись через self: self::MY_CONSTANT
  • отримання значень приватних статичних властивостей ПОВИННО виконуватись через self: self::$_events
  • Дозволено використовувати self для рекурсії, щоб викликати поточне втілення знову замість розширення реалізації класу.

Значення для "не робити чогось"

Властивості, яким дозволено сконфігурувати компонент не робити чогось, повинні приймати значення false. Значення null, '' чи [] не повинні вважатись такими.

Імена директорій та просторів імен

  • використовуйте нижній регістр
  • використовуйте форму множини для іменників, які представляють об’єкти (наприклад, validators)
  • використовуйте форму однини для імен, які представляють відповідну функціональність/можливості (наприклад, web)