Версия для печати

Архив документации на OpenNet.ru / Раздел "PHP" (Многостраничная версия)

Стандарты оформления кода PHP

Оригинал: tony2001.phpclub.net
Содержание
I. Введение
1. Почему стандартизация так важна
2. Принятие стандарта
II. Формирование имён
3. Выбирайте правильные имена
4. Имена классов
5. Имена методов
6. Имена аргументов в методах
7. Имена переменных
8. Имена элементов в массивах
9. Одиночные и двойные кавычки
10. Глобальные переменные
11. Имена функций
III. Форматирование
12. Правила расстановки фигурных скобок
13. Правила расстановки скобок () рядом с операторами и функциями
14. Правила по отступам/табуляциям/пробелам
15. Форматирование блоков if then else
16. Формат switch
17. Использование continue, break и ?:
18. Выравнивание блоков объявления переменных
IV. Документация
19. Несколько комментариев по комментариям
20. Формат описания gotchas
21. Зарезервированные слова для описания gotchas
22. Документация интерфейсов и реализаций
23. Документация по директориям
V. Разное
24. Повторное использование кода
25. Временное комментирование больших блоков

Глава 19. Несколько комментариев по комментариям

Комментарии должны быть содержательными

Воспринимайте комментарии как описание вашей системы. Будьте готовы к тому, что ваши комментарии будут извлечены роботом из текста исходника и оформлены в виде технического руководства. Комментарии к классам станут одной частью описания, сигнатуры методов - другой частью, аргументы методов - третьей, реализации методов - четвёртой. Все эти части должны слиться в единое целое и информировать удалённого в пространстве и времени читателя о том, что именно вы сделали и почему.

Документируйте принятые решения

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

Используйте заголовки

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

Структура заголовков обеспечивает их анализ и извлечение из исходника -структурированные заголовки уже приносят пользу, в отличие от обычных. Поэтому рекомендуется потратить немного времени на их заполнение - и документирование вам больше не понадобится.

Стиль комментариев

Каждая часть проекта имеет свой особый стиль комментариев.

Явно указывайте на gotchas ["ловушки" в коде]

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

Глава 23. Документация по директориям

В каждой директории проекта должен находиться файл README с описанием следующих моментов:

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

Глава 20. Формат описания gotchas

Ключевое слово gotcha должно ставиться в самом начале комментария.

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

Комментарий должен включать в себя имя автора и дату замечания. Эти сведения содержатся и в документации исходников, но иногда бывает трудно их отыскать. Иногда случается, что потенциально опасный участок кода слишком долго не исправляется. Дата gotcha позволяет определить такие места. Указание на автора gotcha показывает, с кого нужно спросить.

Пример

// :TODO: tmh 960810: возможны проблемы со скоростью работы
// Нам точно понадобится хэш-таблица, но пока
// мы используем линейный поиск.

// :KLUDGE: tmh 960810: потенциально небезопасное приведение типа
// Приведение понадобилось для восстановления производного типа. Возможно
// здесь понадобится виртуальный метод или шаблон.

См. также: Документация интерфейсов и реализаций.

IV. Документация

Глава 22. Документация интерфейсов и реализаций

Существует два вида читателей для вашей документации:

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

Пользователи класса

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

Разработчики класса

Разработчикам класса требуется глубокое знание реализации класса. Комментарии этого типа находятся в файлах с исходным кодом класса; забудьте на время про особенности интерфейса. Заголовочный блок комментариев в исходнике должен описать все особенности алгоритма и решения по проектированию класса. Блоки комментариев внутри методов реализации должны предоставить ещё более подробную информацию.

Глава 21. Зарезервированные слова для описания gotchas

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

Из трёх существующих стилей расстановки фигурных скобок допустимы два, причём первому рекомендуется отдавать предпочтение:

  1. открывающая скобка ставится под соответствующим оператором и на одном отступе с ним:

  2. Unix-стиль расстановки фигурных скобок, когда открывающая скобка ставится на одной строке с соответствующим оператором, а закрывающая - на одном отступе с оператором:

Обоснование

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

Преимущество первого стиля заключается не только в психологии. Если вы используете текстовый редактор (например, vi), поддерживающий проверку на парность скобок, первый стиль будет более удобен. Почему? - спросите вы. Допустим, вы наткнулись на большой блок кода и желаете узнать, где же он заканчивается. Наводите курсор на открывающую скобку, жмёте нужную кнопку и редактор находит парную скобку.

Пример

if ($very_long_condition && $second_very_long_condition) //два очень длинных условия
{
    ...
}
else if (...)
{
    ...
}

Итак, для перемещения от блока к блоку вам понадобится стрелка вниз и кнопка поиска парной скобки. И не надо ёрзать и гнать до конца строки, чтобы там найти ту самую открывающую скобку.

Глава 17. Использование continue, break и ?:

Continue и break

Continue и break - это тот же самый goto, только названы по-другому. Именно поэтому они рассмотрены в этой части документа.

Как и goto, continue и break творят всякие разные чудеса в коде, поэтому их использование рекомендуется свести до минимума. Одним мановением руки читатель кода переносится бог знает куда по какой-то незадокументрированной причине. При использовании continue возникают две проблемы:

Пример

Представим себе ситуацию, где имеют место обе проблемы:

while (TRUE)         
{
   ...
   // Много кода
   ...

   if (/* какое-то условие */) {
      continue;
   }
   ...

   // Много кода
   ...
   if ( $i++ > STOP_VALUE) break;
}

Note: "много кода" нужно для того, чтобы программист не смог легко отследить проблему.

Из приведённого выше примера мы можем составить себе следующее правило: использование continue и break в одном блоке - прямая дорога к багам.

?:

Проблема обычно заключается в том, что люди пытаются запихать слишком много кода между ? и :. Вот несколько правил:

Пример

(условие) ? funct1() : func2();

or

(условие)
    ? длинный блок
    : ещё один длинный блок;

Глава 18. Выравнивание блоков объявления переменных

Блок объявления переменных должен выравниваться

Обоснование

Пример

var       $mDate
var&      $mrDate
var&      $mrName
var       $mName

$mDate    = 0;
$mrDate   = NULL;
$mrName   = 0;
$mName    = NULL;

III. Форматирование

Глава 15. Форматирование блоков if then else

Внешний вид

На вкус программиста. Разный стиль расстановки фигурных скобок обусловит немного разный внешний вид условных блоков. Вот один из распространённых стилей:

if (condition)                 // Комментарий
{
}
else if (condition)            // Комментарий
{
}
else                           // Комментарий
{
}

Если у вас в условном блоке есть else if, то стоит поставить else для всех необработанных значений. Даже если не предпринимаются никакие действия, это может быть простая запись в лог.

Формат условия

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

if ( 6 == $errorNum ) ...

Первая причина такому поведению - это то, что парсер найдёт ошибку, если вы поставите только один знак равенства ('=') вместо двух. Вторая причина - при чтении кода вы находите нужное вам значение сразу в начале условия, а не ищите где-то в конце. К такому формату привыкаешь не сразу, но этот стиль действительно полезен.

Глава 13. Правила расстановки скобок () рядом с операторами и функциями

Обоснование

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

Пример

if (condition)
{
}

while (condition)
{

}

strcmp($s, $s1);

return 1;

Глава 16. Формат switch

Пример

switch (...)
{
    case 1:
        ...

      // УПРАВЛЕНИЕ ПЕРЕДАЁТСЯ ВНИЗ

    case 2:
    {
        $v = get_week_number();
         ...
    }
    break;

    default:
}

Глава 14. Правила по отступам/табуляциям/пробелам

Обоснование

function func()
{
    if (something bad)    //не подходит
    {
        if (another thing bad)  //тоже не подходит
        {
            while (more input)  //ещё код
            {
            }
        }
    }
}

Глава 2. Принятие стандарта

Трактовки

Наличие слова "обязательно" означает, что все проекты, использующие этот документ, должны придерживаться этого правила.

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

Слово "рекомендуется" схоже по смыслу со вторым пунктом в том, что правило применяется по возможности.

Принудительное принятие

Прежде всего, любые, хоть сколько-нибудь важные решения по стандартизации желательно принимать коллективно. Может быть для вашей конкретной ситуации такой стандарт не подходит: возможно, сам стандарт не учитывает какие-то важные моменты; возможно, те или иные проблемы упорно игнорируются кем-то главным :-) В любом случае, как только стандарт будет-таки утверждён, все поведут себя как взрослые люди и поймут, что в навязанных им правилах есть здравый смысл; что если эти правила подходят для многих программистов, то стоит их придерживаться, пусть и с некоторыми оговорками.

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

Если и это не проходит, то остаётся потворствовать всем предложениям и идеям противника.

Этапы принятия идеи

  1. Это невозможно.

  2. Может быть, это как-то и получится, но всё это слабовато и неинтересно.

  3. Именно так надо делать, я вам говорю.

  4. Да, сначала я подумал именно об этом.

  5. Иначе и быть не может.

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

Глава 6. Имена аргументов в методах

Обоснование

Всегда можно легко определить, какие переменные поступили в метод в качестве аргумента.

Пример

class NameOneTwo
{
    function StartYourEngines(&$someEngine, &$anotherEngine) {
        $this->mSomeEngine = $someEngine;
        $this->mAnotherEngine = $anotherEngine;
    }

    var $mSomeEngine;
    var $mAnotherEngine;
}

I. Введение

Глава 1. Почему стандартизация так важна

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

Положительные моменты

Когда проект пытается принять тот или иной общепринятый стандарт, случаются следующие хорошие вещи:

Отрицательные моменты

Плохие вещи тоже случаются:

Обсуждение

Опыт многих проектов приводит нас к следующему заключению: с введением стандартов проект продвигается быстрее. Но тогда получается, что стандарты - залог успеха? Конечно, нет. Но они способствуют успеху, а нам нужно использовать все возможности! Будем честны с собой: большинство аргументов против того или иного стандарта исходит от нашего самолюбия. В хорошем стандарте редко случается найти ограничение, которое отрицательно сказалось бы на качестве проекта, в большинстве своём всё это - лишь дело вкуса. Итак, проявите больше гибкости, контролируйте своё самолюбие и помните, что проект продвигается единой командой, а не отдельными программистами.

Глава 25. Временное комментирование больших блоков

Иногда при тестировании возникает необходимость закомментировать большой блок кода. Самый простой способ - это заключение блока в конструкцию if(0):

function example()
{
    роскошный код

    if (0) {
        много кода
    }

    ещё больше кода
}

Комментарии /**/ вы использовать не можете, потому что комментарии не могут содержать комментарии, а большой блок вашего кода непременно будет содержать комментарии, ведь так?

V. Разное

Глава 24. Повторное использование кода

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

Разработка проектного каркаса отнимает много сил и времени. Но даже если по каким-то причинам вы не создали себе подобной системы, существует несколько приёмов поощрения повторного использования кода.

Не бойтесь маленьких библиотек

Один из врагов повторного использования кода - тот факт, что люди не составляют из своего кода библиотеки. Класс многократного использования может быть похоронен в директории одной из программ и может никогда не испытать волнующего чувства реинкарнации в новом проекте. И только потому, что программист не соизволил вынести этот класс (или классы) в библиотеку.

Одна из причин трагедии: люди не любят маленькие библиотеки. Есть в маленьких библиотеках нечто такое, что люди считают неправильным. Подавите в себе это чувство. Компьютеру абсолютно всё равно, сколько у вас библиотек.

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

Держите свою базу библиотек [репозиторий]

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

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

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

Глава 8. Имена элементов в массивах

Обоснование

Если в качестве разделителя используется дефис, то при включении опции Magic Quotes вы получите сообщения об ошибках.

Пример

$myarr['foo_bar'] = 'Hello';
print "$myarr[foo_bar] world"; // выведет: Hello world

$myarr['foo-bar'] = 'Hello';
print "$myarr[foo-bar] world"; // получим warning

Глава 4. Имена классов

Обоснование

Из всех других вариантов многие выбрали этот как лучшее компромиссное решение.

Пример

class NameOneTwo
class Name

Глава 11. Имена функций

Обоснование

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

Пример

function some_bloody_function()
{
}

Глава 10. Глобальные переменные

Обоснование

Такой префикс необходим для определения области действия переменных

Пример

global $gLog;
global &$grLog;

II. Формирование имён

Глава 3. Выбирайте правильные имена

Имена - сердце программирования. В прошлом люди верили, что если узнать настоящее имя человека, можно получить власть над ним. Если вы подберёте правильные имена, вы наделите себя и других (всех, кто придёт после вас) властью над кодом. Просьба не смеяться, всё серьёзно.

Имя является результатом продолжительного осмысления мира, в котором "живёт" тот или иной объект. Только тот программист, который понимает систему в целом, в состоянии дать объектам имена, вписывающиеся в концепцию создаваемой системы. Если имя подобрано правильно, то всё стоит на своих местах, отношения между объектами ясны, значения легко угадываются и все человеческие мотивировки и ожидания срабатывают как хотелось бы.

И если вы вдруг обнаружили, что все объекты вашего кода называются Фигня и Штуковина, то такой код вам стоит серьёзно пересмотреть.

Глава 5. Имена методов

Как правило функция или метод совершают какое-либо действие, поэтому желательно, чтобы из имени было понятно, какое именно действие будет совершаться: CheckForErrors() [ИщиОшибки()] вместо ErrorCheck() [ПоискОшибок()]; DumpDataToFile() [СваливайДанныеВФайл()] вместо DataFile()[ФайлДанных()]. Кроме того, так легче будет отличить метод от класса.

Иногда помогают суффиксы:

Префиксы тоже иногда нелишни:

Например: IsHitRetryLimit() [примерно: это ли последняя попытка?].

Никаких аббревиатур заглавными буквами

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

Неправильно: GetHTMLStatistic().

Правильно: GetHtmlStatistic().

Обоснование

При формировании имён, содержащих сокращения, люди используют свои интуитивные системы по-разному, поэтому лучше придерживаться единой стратегии формирования имён для всех случаем и добиться тем самым предсказуемости именования. Возьмём, к примеру, NetworkABCKey. Заметьте, что C от ABC и K от Key воспринимаются больше как буквенное сочетание. В принципе, некоторые не возражают против аббревиатур целиком из заглавных, другие же их просто ненавидят; так что в разным проектах люди придерживаются разных стратегий.

Пример

function FluidOz()      //а не FluidOZ
function GetHtmlStatistic()     //а не GetHTMLStatistic    

class NameOneTwo
{
    function DoIt() {};

    function HandleError() {};
}

Глава 9. Одиночные и двойные кавычки

Осуществляя доступ к элементам массива, можете использовать как одинарные, так и двойные кавычки. Не используйте кавычки при включённой опции Magic Quotes.

Обоснование

За исключением случаев использования Magic Quotes, некоторые конфигурации PHP выдают сообщение об ошибке, если при доступе к элементам массива кавычки опускаются.

Пример

$myarr['foo_bar'] = 'Hello';
$element_name = 'foo_bar';
print "$myarr[foo_bar] world"; // выведет: Hello world
print "$myarr[$element_name] world"; // выведет: Hello world
print "$myarr['$element_name'] world"; // parse error
print "$myarr["$element_name"] world"; // parse error

Глава 7. Имена переменных

Обоснование

Пример

function HandleError($errorNumber)
{
    $error = new OsError;
    $time_of_error = $error->GetTimeOfError();
    $error_processor = $error->GetErrorProcessor();
}