Perl code style — различия между версиями

Материал из YourcmcWiki
Перейти к: навигация, поиск
Строка 238: Строка 238:
 
             ON table2.x=table.x
 
             ON table2.x=table.x
 
         WHERE table.x=?
 
         WHERE table.x=?
");
+
", undef, $x);
 +
</code-perl></s>
 +
 
 +
ВСЕГДА следует использовать bind-переменные, и лишь только в крайнем случае — <tt>$dbh->quote()</tt>.
 +
 
 +
Желательно использовать методы <tt>$dbh->select***</tt> и помнить о <tt>{Slice=>{}}</tt>, дающем возможность получить строчки из БД в самом удобном виде — в виде ссылки на массив хешрефов, например,
 +
 
 +
<code-perl>
 +
selectall_arrayref("SELECT * FROM table WHERE x=?", {Slice=>{}}, $var1);
 +
</code-perl>
 +
 
 +
Для получения ссылки на массив со значениями первой колонки — <tt>$dbh->selectcol_arrayref</tt>; для получения первой строчки в виде списка — <tt>$dbh->selectrow_array</tt>; иногда можно применять и <tt>$dbh->selectall_hashref</tt>.
 +
 
 +
При этом нежелательно без крайней необходимости использовать пары prepare/execute и длинные списки переменных вместо хешей:
 +
 
 +
<s><code-perl>
 +
my $sth = $dbh->prepare("SELECT ...");
 +
$sth->execute($var);
 +
while (my ($field1, $field2) = $sth->fetchrow_array)
 +
{
 +
    ...
 +
}
 
</code-perl></s>
 
</code-perl></s>

Версия 15:35, 14 октября 2014

Отступы и пробелы

Размер отступа — строго 4 пробела либо 1 таб. Никаких смесей пробелов и табов — ни для «симуляции половины таба» (запрещается стиль кода, где один отступ = 4 пробела, а 2 отступа = 1 таб), ни для выравнивания условий if () или параметров функций по открывающейся скобке. Если в файле пробелы, то только пробелы; если табы — то только табы.

Каждый уровень выравнивается строго на +1 отступ.

Например, продолжение выражения на новой строке всегда выравнивается ровно на +1 отступ. Именно на +1, а не на половину или ещё сколько-то:

$template->process('file.tmpl', $vars)
    || ThrowTemplateError($template->error);

Второй пример — если список параметров функции не помещается на 1 строчку — он переносится на следующую строчку с одинарным отступом, а закрывающая скобка помещается на отдельную строчку без отступа:

$self->example(
    'very long parameter', 'very long parameter', 'very long parameter', 'very long parameter'
);

Например, вот так НЕ ПИШЕМ НИКОГДА (отступы всегда должны расти ровно на 1 уровень!):

$self->example('very long parameter', 'very long parameter',
               'very long parameter', 'very long parameter');

Тело блока всегда глубже открывающих/закрывающих конструкций и скобок ровно на 1 отступ. Есть, например, такой вот странный вариант — так НЕ ПИШЕМ НИКОГДА:

if ($a)
    {
    ...
    }

После ключевых слов for, if и подобных всегда следует пробел:

for (my $a = 0; $a < 100; $a++) ...

После открывающих и перед закрывающими скобками пробелы НЕ СТАВЯТСЯ. То есть вот так не пишем НИКОГДА:

if ( $a == 1 ) ...

Пробелами обрамляется большинство операторов — присваивания, сравнения, логические, арифметические и т. п. Исключение могут составлять слагаемые в арифметических выражениях, например, $a*10 + 5.

Блоки

Фигурные скобки ВСЕХ блоков, содержащих более 1 оператора, начинаются с новой строки:

sub x
{
    ...
    if (...)
    {
        ...
    }
    else
    {
        ...
    }
    ...
}

Если блок содержит только 1 оператор и этот оператор очень короткий, его можно разместить на 1 строке:

eval { &$sub() };

Конструкции map { … } и grep { … } желательно записывать в 1 строку. Если условие очень длинное — либо превратить в цикл for(), либо записать условие на отдельных строчках, оставив фигурную скобку на той же строке, что и grep:

grep {
    ... &&
    ... &&
    ...
} @array

Если блок содержит несколько операторов, можно даже перенести фигурную скобку { на новую строку:

map
{
    my $a = $_;
    $a =~ s/[abc]/a/g;
    $a;
} @array

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

my $hash = {
    ...
};

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

В случае, если тело цикла — пустое, следует всегда явно добавлять пустой блок вместо пустого оператора «;»:

for ($a = 0; $s{$a}; $a++) {}

вместо

for ($a = 0; $s{$a}; $a++);

Perl

Общее правило: поменьше «синтаксического плюрализма», то есть всяких извращённых вариантов записи, в целом позволяемых Perl’ом. Лучше, чтобы все конструкции выглядели однозначно.

Всегда следует использовать

use strict;

Для строк не следует использовать синтаксис q{}, qq{}. Обычных кавычек ('' и "") вполне достаточно. HEREDOC — разрешён, но на крайний случай, для очень длинных строк.

Суффиксная запись if/unless/for допускается только для очень коротких одинарных и однострочных операторов. Даже если тело if’а или for’а однострочное, но условие длинное и его приходится переносить на следующую строчку — лучше предпочесть обычную запись с фигурными скобками. Если тело выглядит слишком коротким — лучше заставить себя добавить к нему комментарий:

if (!($a = $self->_template_lang_directories(Bugzilla->languages, "extensions/BmpConvert")))
{
    # комментарий
    $self->_search_templates(Bugzilla->languages, "extensions/BmpConvert");
}

Вместо

$self->_search_templates(Bugzilla->languages, "extensions/BmpConvert")
    if !($a = $self->_template_lang_directories(Bugzilla->languages, "extensions/BmpConvert"));

Частный случай: НИ В КОЕМ СЛУЧАЕ не должны использоваться конструкции вида (во vsem.ru, помню, работал какой-то любитель такого):

do
{
    ...
} if (...);

Проверки на пустоту/непустоту следует делать БЕЗ дополнительных scalar(), keys(), == 0, > 0 и т. п. То есть, например, вместо:

if (scalar(@array) == 0) {}
if (scalar(keys(%$hash)) > 0) {}
if ($a == 0) {}

Следует писать:

if (!@array) {}
if (%$hash) {}
if (!$a) {}

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

keys %hash;
scalar @array;
push @array, "value";

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

open(FD, "file") or die.

Вместо операторов and, or, not предпочтительно использовать C-подобные &&, ||, !. Даже если and/or требуются согласно приоритету операторов, то вполне возможно, что конструкцию лучше переписать так, чтобы можно было использовать «нормальные» операторы && или ||, так как это, вероятно, устранит её «визуальную» неоднозначность. Например, добавить скобки:

($a = $b) || return

вместо

$a = $b or return

Вместо простых массивов/хешей желательно везде использовать ссылки на массивы/хеши: в переменных, в параметрах функций, в значениях возврата… Простые массивы и хеши имеет смысл использовать только там, где это действительно необходимо (что случается очень редко).

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

Также предпочтительно НЕ использовать возврат списков и wantarray в функциях — лучше вернуть ссылку на массив или хеш.

Аргументы функции строго рекомендуется получать в её начале с помощью списочного присваивания, причём желательно с отдельной строкой my $self = shift — это помогает визуально отличать функции и методы:

sub f
{
    my $self = shift;
    my ($arg1, $arg2) = @_;
    ...
}

В принципе, также можно применять конструкцию

my ($self, $arg1, $arg2) = @_;

Другие конструкции (например, несколько shift подряд) допустимы, если это необходимо для удобства «разворачивания» остальных атрибутов функции.

Ключи хешей, которые можно записать БЕЗ кавычек, ВСЕГДА следует записывать БЕЗ кавычек. Кавычки следует добавлять только тогда, когда это действительно необходимо — то есть, если ключ содержит разделители (например, $hash{'a-b'}).

Обращение к вложенным ключам в ссылке на массив/хеш записывается через ->:

$hash->{key}->{key}->{key}

Обращение к вложенным ключам в списке или хеше (не в ссылку на массив/хеш) записывается без ->:

$hash{key}{key}{key}

Длинные SQL операторы следует записывать в несколько строк с конкатенацией и пробелом в начале продолжения каждой новой строки:

$dbh->do(
    "SELECT field1, field2, field3, field4" .
    " FROM table" .
    " INNER JOIN table2 ON table2.x=table.x" .
    " WHERE x=?",
    undef, $x
);

А не, например, вот так (помним, что отступы всегда растут ровно по 1 уровню):

$dbh->do("
        SELECT field1, field2, field3, field4
          FROM table
    INNER JOIN table2
            ON table2.x=table.x
         WHERE table.x=?
", undef, $x);

ВСЕГДА следует использовать bind-переменные, и лишь только в крайнем случае — $dbh->quote().

Желательно использовать методы $dbh->select*** и помнить о {Slice=>{}}, дающем возможность получить строчки из БД в самом удобном виде — в виде ссылки на массив хешрефов, например,

selectall_arrayref("SELECT * FROM table WHERE x=?", {Slice=>{}}, $var1);

Для получения ссылки на массив со значениями первой колонки — $dbh->selectcol_arrayref; для получения первой строчки в виде списка — $dbh->selectrow_array; иногда можно применять и $dbh->selectall_hashref.

При этом нежелательно без крайней необходимости использовать пары prepare/execute и длинные списки переменных вместо хешей:

my $sth = $dbh->prepare("SELECT ...");
$sth->execute($var);
while (my ($field1, $field2) = $sth->fetchrow_array)
{
    ...
}