Описанный ниже стиль кодирования используется при разработке ядра Cotonti и его официальных расширений. Если вы хотите участвовать в разработке системы, постарайтесь придерживаться данного стиля. Мы не принуждаем вас использовать этот стиль при разработке ваших приложений с использованием Cotonti. В этом случае вы можете использовать тот стиль, который вам больше подходит.
Эти основные правила касаются всех файлов с программным кодом в проекте (HTML, PHP, CSS, JS и т.д.), если не оговорено другое.
- Файлы с кодом ДОЛЖНЫ содержать только символы в кодировке UTF-8 без BOM.
- Символ перевода строки ДОЛЖЕН быть LF.
- Для выравнивания кода НУЖНО использовать 4 пробела вместо табуляции. (todo или наоборот, не определился еще)
- В конце строк не должно быть лишних пробелов. (настройте Ваш редактор на удаление пробелов в конце сток при сохранении файла).
Нет жесткого органичения длины строки, но желательно чтобы строки не превышали 120 символов. Переносить строку следует там, где это имеет наибольший смысл, а не тогда, когда ее длина приближается к 120 символам.
…в дополнение к основным правилам:
PHP код должен следовать стандарту написания кода PSR-12, и PSR-1, и стандарту автозагрузки php-файлов PSR-4.
Если вы используете PHPStorm, вы можете включить инструменты для форматирования кода в
Settings
→ Editor
→ Code Style
→ PHP
→ Set from
→ PSR12
.
- Открывающие теги ДОЛЖНЫ быть только
<?php
или<?=
и НЕ ДОЛЖНО использоваться никаких других вариаций тегов, например<?
. - Если файл содержит только PHP код, то закрывающий тег
?>
не нужен. - Все операторы ДОЛЖНЫ иметь по одному пробелу до и после оператора, за исключением инкремента/декремента, например
$a + $b
,$string = $foo . 'bar'
,$i++
но не$a+$b
. - Используйте один пробел после запятой
$one, $two
, но не$one,$two
. - Используйте операторы строго равенства
===
и неравенства!==
. - Однострочные комментарии ДОЛЖНЫ начинаться с
//
, а не с#
. - Избегайте использования глобальных переменных. Не используйте неопределенные переменные.
- Информации по синтаксису документации PHPDoc.
- Код без документации недопустим.
- Все файлы классов должны содержать блок документации в начале файла и блок документации непосредственно перед каждым классом.
Все PHP файлы в самом начале должны содержать описание в формате PHPDoc.
Очень хорошо, когда в заголовке описаны переменные, которые используются в этом файле, в определены где-то в другом месте.
Стандартный заголовок для файлов (этот шаблон заголовка должен быть в начале каждого файла Cotonti):
/**
* @package {PACKAGENAME}
* @version {VERSION}
* @copyright (c) 2008-2023 Cotonti Team
* @license BSD License
*
* @var array<string, mixed> $user
* @var XTemplate $t
*/
@version
- не обязательно. Например, если вы создаете расширение, версия уже прописана в установочном файле и тег
@version
может "путать" других разработчиков.
Не забывайте документировать классы. Классам нужен свой тег @package, тот же что и в заголовке.
/**
* Cotonti MySQL Database adapter class.
* A compact extension to standard PHP PDO class with slight Cotonti-specific needs,
* handy functions and query builder.
*
* @package cotonti
* @see http://www.php.net/manual/en/class.pdo.php
*
* @property-read int $affectedRows Number of rows affected by the most recent query
* @property-read int $count Total query count
* @property-read int $timeCount Total query execution time
*/
class MySQL extends Adapter
Документируйте функции. Каждая функция должна как минимум иметь описание того, что она делает. Также рекомендуется
документировать параметры. Используйте @param
, @return
, @throws
в таком порядке.
/**
* Returns total number of records contained in a table
* @param string $tableName Table name
* @return int
* @throws Exception if the table name is exists
*/
public function countRows($tableName)
Все имена должны быть описательными, но краткими. Читая имя класса или переменной должно быть понятно зачем они нужны.
Например: $currentUser
, getUserData($id)
Имена классов ДОЛЖНЫ быть в PascalCase. Например: Controller
, Model
.
Константы ДОЛЖНЫ быть в верхнем регистре со знаком подчеркивания в качестве разделителя слов. Например:
STATUS_PUBLISHED
.
Названия папок/пространств имен в нижнем регистре.
Мы НЕ ИСПОЛЬЗУЕМ нижнее подчеркивание для обозначения приватных свойств и методов классов.
Имена переменных ДОЛЖНЫ быть в camelCase. Каждое слово, кроме первого, должно начинаться с заглавной буквы.
Например: $currentUser
- правильно, а $current_user
и $currentuser
- нет.
Ситуации, когда допускаются односимвольные имена для переменных: языковые строки: $L
, строковые ресурсы: $R
и когда
переменная является индексом для цикла.
Индексы циклов:
В этом случае индекс цикла верхнего уровня всегда должен быть $i
. Если цикл содержит вложенный цикл, его индекс
должен быть $j
, далее $k
и т.д. Если индексом цикла является какая-либо существующая переменная, то это правило не
применяется. Например:
for ($i = 0; $i < $outerSize; $i++) {
for ($j = 0; $j < $innerSize; $j++) {
foo($i, $j);
}
}
Имена функций и методов переменных ДОЛЖНЫ быть в camelCase. Исключение - функции ядра Cotonti. Пример хороших имен
функций: printLoginStatus()
, getUserData()
, и т.п.
В Cotonti мы используем стандартный префикс cot_
для всех имен функций, чтобы избежать конфликта имен.
Это стандарт для функций API ядра системы: cot_mailPrepareAddress($address)
.
Но мы не требуем использовать префикс cot_
в ваших расширениях до тех пор, пока эти функции не используются функциями
ядра. При желании вы можете использовать свой префикс.
Для аргументов функций используются те же правила что и для имен переменных.
Основная философия здесь заключается в том, чтобы не нарушать читабельность и понятность кода из-за лени. Но тут
нужно соблюдать баланс и следовать здравому смыслу. Например printLoginStatusForAGivenUser()
будет уже через чур.
Вот это название функции будет лучше: printUserLoginStatus()
, или просто printLoginStatus()
.
Все типы данных и значения PHP должны быть в нижнем регистре. Это относится и к true
, false
, null
.
Для приведения типов мы используем операторы, а не функции. И только их короткие формы. После оператора ставим один пробел.
$value1 = (int) $argument1; // верно
$value2 = (bool) $argument2; // верно
$value3 = (integer) $argument3; // не верно
$value4 = invtal($argument2, 8); // только если это действительно необходимо
Изменение типа существующей переменной считается плохой практикой. Постарайтесь не использовать такой подход, за исключением случаев, когда это действительно необходимо.
public function save(Transaction $transaction, $argument2 = 100)
{
$transaction = new Connection; // плохо
$argument2 = 200; // хорошо
}
Если строка не содержит переменных или одинарных кавычек, используйте одинарные кавычки.
$str = 'Например так.';
Если строка содержит одинарную кавычку, используйте двойные кавычки во избежание излишнего экранирования.
$str1 = "Привет, $username!";
$str2 = "Привет, {$username}!";
Следующий вариант запрещен:
$str3 = "Привет, ${username}!";
При конкатенации строк выделяйте точку пробелами:
$name = 'Cotonti' . ' CMF';
Для длинных строк используйте следующий подход:
$sql = 'SELECT * '
. 'FROM post '
. 'WHERE id = 121 ';
Для массивов мы используем краткий синтаксис.
$arr = [3, 14, 15, 'Cotonti', 'CMF'];
При большом количестве элементов, каждый элемент располагается на отдельной строке. После последнего элемента СТАВИМ запятую.
$mail = [
'to' => '[email protected]',
'from' => ['[email protected]', 'SiteTitle'],
'cc' => [['[email protected]', 'User2'], '[email protected]', 'User4 <[email protected]>'],
];
- Управляющие конструкции ДОЛЖНЫ содержать по одному пробелу перед открывающей круглой скобкой и после закрывающей круглой скобки.
- Операторы внутри круглых скобок ДОЛЖНЫ разделяться одним пробелом с обеих сторон.
- Открывающая фигурная скобка ДОЛЖНА быть на той же строке.
- Закрывающая фигурная скобка ДОЛЖНА быть на новой строке.
- ВСЕГДА используйте фигурные скобки, даже для однострочных выражений.
if ($expr1) {
// if body
} elseif ($expr2) {
// elseif body
} else {
// else body;
}
// Такой код недопустим:
if (!$model && null === $event) throw new Exception('test');
Всегда ДОЛЖНО использоваться elseif
а не else if
. Т.е. все ключевые слова состоят из одного слова.
Длинные выражения в скобках разбивайте на несколько строк, где каждая строка имеет как минимум один отступ. В этом случае первое условие ДОЛЖНО быть на следующей строке. Закрывающая круглая скобка и открывающая фигурная ДОЛЖНЫ быть на своей отдельной строке с одним пробелом между ними. Булевы операторы между условиями всегда ДОЛЖНЫ быть в начале строки.
if (
$expr1
&& $expr2
) {
// if body
}
Избегайте использования else
после ключевого слова return
:
$result = $this->getResult();
if (empty($result)) {
return false;
} else {
// process result
}
Так на много лучше:
$result = $this->getResult();
if (empty($result)) {
return false;
}
// process result
Конструкция switch
выглядит следующим образом. Обратите внимание на расположение пробелов, круглых и фигурных скобок.
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;
}
Тернарные операторы следует использовать только для очень простых вещей. Желательно, чтобы они использовались только для присваивания значений, а не для вызовов функций или чего-то более сложного. Иначе это вредит читабельности кода и усложняет отладку. Примеры:
// Так плохо
($i < $size && $j > $size) ? do_stuff($foo) : do_stuff($bar);
// А так хорошо
$min = ($i < $j) ? $i : $j;
Здесь под термином "класс" понимаются все классы, интерфейсы и трейты.
- Открывающая фигурная скобка для класса ДОЛЖНА располагаться на отдельной строке; закрывающая фигурная скобка для класса ДОЛЖНА идти на следующей строке после тела класса.
- Имена классов ДОЛЖНЫ быть в PascalCase.
- У каждого класса ДОЛЖЕН быть блок документации соответствующий PHPDoc
- В одном php файле должен быть только один класс.
- У каждого класса должно быть пространство имен.
- Для всех свойств и методов ДОЛЖНА быть объявлена видимость.
- Ключевые слова
extends
иimplements
ДОЛЖНЫ быть объявлены в той же строке, что и имя класса. Списокimplements
(extends
для интерфейсов) может быть разделен на несколько строк, где каждая строка имеет один отступ. При этом первый элемент в списке ДОЛЖЕН находиться в следующей строке, и в каждой строке должен быть только один интерфейс.
Общедоступные (public) и защищенные (protected) свойства должны быть объявлены в начале класса, раньше объявления методов; Закрытые (private) свойства, так же, должны быть объявлены в начале класса, но могут быть добавлены и непосредственно перед методами, использующими их, в случае, если эти переменные используются только небольшой частью методов класса.
<?php
/**
* Doc блок файла
*/
namespace Vendor\Package;
use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;
/**
* Doc блок класса
*/
class ClassName extends ParentClass implements \ArrayAccess, \Countable
{
public $publicProp1;
public $publicProp2;
protected $protectedProp;
private $_privateProp;
public function someMethod()
{
// ...
}
}
Открывающая фигурная кавычка ДОЛЖНА быть расположена на строке, следующей за строкой объявления функции, а закрывающая скобка ДОЛЖНА находиться в следующей строке после тела функции.
В списке аргументов ДОЛЖЕН быть один пробел после запятой.
function foo(int $arg1, &$arg2, $arg3 = [])
{
// тело функции
}
Список аргументов может быть разбит на несколько строк, где каждая строка имеет один отступ. В этом случае первый аргумент ДОЛЖЕН быть на следующей строке и ДОПУСКАЕТСЯ только один агрумент на строку.
public function aVeryLongMethodName(
ClassTypeHint $arg1,
&$arg2,
array $arg3 = []
) {
// тело метода
}
При вызове функции или метода НЕ ДОЛЖНО быть пробела между именем функции и открывающейся скобкой. НЕ ДОЛЖНО быть пробела после открывающейся скобки и перед закрывающейся. В списке аргументов НЕ ДОЛЖНО быть пробела перед запятой и ДОЛЖЕН быть один после
SQL запросы зачастую нечитабельны без форматирования, а временами они бывают очень большими. Форматирование значительно повышает читаемость кода. SQL запросы следует форматировать следующим образом, ориентируясь на ключевые слова:
$sql = 'SELECT p.*, u.* '
. 'FROM ' . Cot::$db->pages . ' AS p ' .
. 'LEFT JOIN ' . Cot::$db->pages . ' AS u ON u.user_id = p.page_ownerid '
. "WHERE p.page_ownerid = 1 AND p.page_cat = 'news' "
. 'LIMIT 10';
Используйте параметры для безопасной подстановки в запрос данных, введенных пользователями (даже если вы уверены, что переменная не может содержать одинарных кавычек. Никогда не доверяйте данным, передаваемым пользователями):
$result = Cot::$db->query(
'SELECT * FROM ' . Cot::$db->forum_topics . ' WHERE ft_cat = :cat AND ft_id = :topicId',
['cat' => $category, 'topicId' => $topicId]
);
- Оператор не равно описанный в стандарте SQL-92 - это
<>
.!=
также поддерживается большинством СУБД, но лучше использовать<>
. INSERT ... ON DUPLICATE KEY UPDATE
- это MySQL конструкция и не работает в других СУБД.- Обратные кавычки
`
для названий таблиц и столбцов - специфично для MySQL. Лучше используйтеCotDB::quoteTableName()
иCotDB::quoteColumnName()
или сокращенные варианты этих методов:CotDB::quoteT()
,CotDB::quoteC()
- Используйте JSDoc для документирования классов, свойств и методов.
- Правила документирования, комментирования, именования применимы от пункта 2. PHP.
- Не используйте jQuery там, где без него можно обойтись.
- Используйте
let
, а неvar
для объявления переменных иconst
для объявления констант. - Константы, которые жёстко заданы всегда, во время всей программы, именуются в верхнем регистре со знаком
подчеркивания в качестве разделителя слов. Например:
const COLOR_ORANGE = "#ffa500"
. Большинство переменных – константы в другом смысле: они не меняются после присвоения. Но при разных запусках функции это значение может быть разным. Для таких переменных следует использоватьconst
и camelCase в имени. - Всегда ставьте точку с занятой в конце строки.
- Всегда используйте строгое сравнение: равенство
===
, неравенство!==
.
- Используйте одинарные кавычки:
let single = 'single-quoted';
. - Если строка содержит одинарную кавычку, используйте двойные кавычки во избежание излишнего экранирования.
- Для подстановки выражений используйте обратные кавычки:
alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3.
.
- PHPStorm Quality Tools
- PHP Static Analysis Tool - обнаружение ошибок в коде не запуская его!
- PHP_CodeSniffer проверка PHP файлов на соотвествие стандартам написания кода.
- Changelog files rules — полезные инструкции по ведению CHANGELOG файлов