Тут показані розбіжності між вибраною ревізією та поточною версією сторінки.
| Порівняння попередніх версій Попередня ревізія | Попередня ревізія | ||
|
codingguidelines [2019/11/07 17:31] |
codingguidelines [2025/09/26 15:14] (поточний) pautina |
||
|---|---|---|---|
| Рядок 1: | Рядок 1: | ||
| + | ====== Ubilling Coding Guidelines & Best Practices або біблія Ubilling ====== | ||
| + | ===== Навіщо це? ===== | ||
| + | Наш проєкт є некомерційним, | ||
| + | |||
| + | * Читабельним | ||
| + | * Оптимізованим | ||
| + | * Тестованим | ||
| + | * Коментованим | ||
| + | * Модульним | ||
| + | |||
| + | Коротко будемо називати ці критерії **Ч.О.Т.К.М.**. Якщо такий набір правил здається вам занадто складним, | ||
| + | |||
| + | * Простота | ||
| + | * Ідіоматичність | ||
| + | * Збереження легасі | ||
| + | * Документованість | ||
| + | * Адаптованість | ||
| + | * Тестованість | ||
| + | * Оптимізованість | ||
| + | |||
| + | Для стислості будемо називати його **П.І.З.Д.А.Т.О.**, | ||
| + | |||
| + | ===== Error reporting ===== | ||
| + | |||
| + | Перед тим, як почати щось писати, | ||
| + | |||
| + | Для початку запам' | ||
| + | |||
| + | <file ini php.ini> | ||
| + | magic_quotes_gpc = Off | ||
| + | magic_quotes_runtime = Off | ||
| + | magic_quotes_sybase = Off | ||
| + | date.timezone=" | ||
| + | |||
| + | display_errors = On | ||
| + | display_startup_errors = On | ||
| + | log_errors = On | ||
| + | log_errors_max_len = 1024 | ||
| + | report_memleaks = On | ||
| + | html_errors = On | ||
| + | memory_limit = 512M | ||
| + | max_input_vars = 50000 | ||
| + | |||
| + | post_max_size = 64M | ||
| + | upload_max_filesize = 64M | ||
| + | </ | ||
| + | |||
| + | Відповідно у вас він має виглядати аналогічним чином. Якщо ви не бачите купи warning & notice, це не означає, | ||
| + | Щодо memory_limit, | ||
| + | |||
| + | Також ваш код має працювати з **error_reporting(E_ALL)**. Якщо з якихось причин він вимагає // | ||
| + | |||
| + | |||
| + | ===== Оформлення коду ===== | ||
| + | |||
| + | ==== Кодування символів ==== | ||
| + | |||
| + | PHP-код повинен бути представлений тільки в кодуванні UTF-8 без BOM-байта. | ||
| + | |||
| + | ==== PHP-теги ==== | ||
| + | |||
| + | PHP-код обов' | ||
| + | |||
| + | |||
| + | ==== Базові конструкції мови та форматування ==== | ||
| + | |||
| + | Особливих вимог немає. Рекомендованою розстановкою фігурних дужок в умовах if, циклах, | ||
| + | |||
| + | <code php> | ||
| + | |||
| + | protected function listUsers() { | ||
| + | if ($userCount >= 0) { | ||
| + | ... | ||
| + | } else { | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | Можливе використання скороченого формату if у випадках, | ||
| + | |||
| + | <code php> | ||
| + | $enableFlag = (wf_CheckGet(array(' | ||
| + | </ | ||
| + | |||
| + | Щодо скорочених AND (&& | ||
| + | |||
| + | На тему табів, відступів та іншого - більшість розробників використовує IDE NetBeans та Visual Studio Code і рефлекторно натискає **Alt+Shift+F** для автоматичного форматування коду. | ||
| + | |||
| + | ==== Іменування змінних та констант ==== | ||
| + | |||
| + | Постарайтеся, | ||
| + | |||
| + | Приклади **гарного іменування змінних**: | ||
| + | |||
| + | <code php> | ||
| + | $allCities = array(); // очевидно, | ||
| + | |||
| + | $allUserData = zb_UserGetAllDataCache(); | ||
| + | |||
| + | $totalUsers = 666; // дуже схоже на лічильник якихось користувачів, | ||
| + | |||
| + | $switchesCount = 12; // лічильник світчів, | ||
| + | |||
| + | $filteredDevices=array(); | ||
| + | |||
| + | $result = 'some string here'; // так, зрозуміло що це результат чогось, | ||
| + | </ | ||
| + | |||
| + | І ось у якому вигляді **категорично не хочеться бачити** роботу зі змінними та їх іменуванням: | ||
| + | |||
| + | <code php> | ||
| + | $a=$b+$c; | ||
| + | |||
| + | $huitka=132/ | ||
| + | |||
| + | $LOLIMHERE=SOMESHIT666(); | ||
| + | |||
| + | $f_ar_type_data=12; | ||
| + | |||
| + | $obj1=$obj2; | ||
| + | </ | ||
| + | |||
| + | Винятком для однобуквового і простого іменування змінних є загальноприйняті та місцево прийняті імена змінних для типових операцій, | ||
| + | |||
| + | <code php> | ||
| + | $i = 0; // стандартний інкрементний або декрементний лічильник, | ||
| + | $total = 0; // загальний лічильник чогось що ми рахували раніше | ||
| + | $count = 0; // приблизно те ж саме за духом | ||
| + | $all = array(); // масив з якимось набором даних, який ми будемо потім перебирати | ||
| + | |||
| + | // Конструкції виду $io => $each є для нас надтиповими на проходах масивів | ||
| + | foreach ($all as $io => $each) { | ||
| + | if (!empty($each)) { | ||
| + | // $ia, $ib... etc для вкладених переборів. | ||
| + | foreach ($each as $ia => $some) { | ||
| + | $total++; | ||
| + | $count++; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | $i++; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | А ось взагалі дуже [[https:// | ||
| + | |||
| + | ==== Іменування класів та об' | ||
| + | |||
| + | Усе досить просто. Рекомендованим є UpperCamelCase/ | ||
| + | |||
| + | Приклад того, як це може виглядати: | ||
| + | <code php> | ||
| + | class SexyUsers { | ||
| + | |||
| + | public function __construct() { | ||
| + | $this-> | ||
| + | } | ||
| + | |||
| + | protected function loadData() { | ||
| + | ..... | ||
| + | } | ||
| + | | ||
| + | public function renderList() { | ||
| + | ..... | ||
| + | } | ||
| + | |||
| + | protected function save() { | ||
| + | ..... | ||
| + | } | ||
| + | |||
| + | } | ||
| + | |||
| + | $sexyUsers = new SexyUsers(); | ||
| + | show_window(__(' | ||
| + | |||
| + | $sexy=new SexyUsers(); | ||
| + | ... | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== Іменування методів і функцій ==== | ||
| + | |||
| + | Правила також прості й очевидні. У старому функціональному коді використовувалися функції з префіксом **zb_** і Upper/Lower CamelCase іменуванням вигляду zb_[Сутність][Що робить? | ||
| + | |||
| + | Приклад: | ||
| + | |||
| + | <code php> | ||
| + | // так, відноситься до роботи з " | ||
| + | |||
| + | function zb_AddressChangeCityName($cityid, | ||
| + | ... | ||
| + | </ | ||
| + | |||
| + | |||
| + | Або з префіксом **web_** для функцій призначених для рендеру результатів чогось. | ||
| + | |||
| + | Приклад: | ||
| + | <code php> | ||
| + | // так, повертає селектор вулиць для використання у формочках | ||
| + | function web_StreetSelector($cityid) { | ||
| + | ... | ||
| + | </ | ||
| + | |||
| + | Також варто утриматися від іменування функцій іменами, | ||
| + | |||
| + | Приклад того, як не варто робити: | ||
| + | |||
| + | <code php> | ||
| + | function file_put_content($data) { | ||
| + | ... | ||
| + | } | ||
| + | |||
| + | | ||
| + | </ | ||
| + | |||
| + | Найкращими для іменування функцій є camelCase або snake_case у крайньому разі. Також бажано, | ||
| + | |||
| + | Приклад **поганого** іменування функції, | ||
| + | |||
| + | <code php> | ||
| + | function zaebisfunkciyamadebyvasya($x) { | ||
| + | ... | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | |||
| + | А з методами всередині класів що? Найкращим іменуванням є lowerCamelCase або односкладовий lowercase. Який вигляд це має можна подивитися вище, на прикладі оголошення class SexyUsers. А саме якось так: | ||
| + | |||
| + | <code php> | ||
| + | protected function loadData() { | ||
| + | ..... | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Область видимості (protected/ | ||
| + | |||
| + | ==== Іменування аргументів методів і функцій ==== | ||
| + | |||
| + | див. [[codingguidelines# | ||
| + | |||
| + | ==== Іменування опцій у конфігах ==== | ||
| + | |||
| + | Просто зазирніть у файли конфігурації типу [[alteriniconf|alter.ini]] і усвідомте, | ||
| + | |||
| + | Приклад того, як це має виглядати: | ||
| + | <code ini> | ||
| + | ;This option enables sexy users support | ||
| + | SEXY_USERS_ENABLED=1 | ||
| + | ;sexy users configuration | ||
| + | SEXY_OPTION=" | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== Збереження Legacy ==== | ||
| + | |||
| + | **Щодо збереження легасі на рівні передбачуваності поведінки системи**: | ||
| + | |||
| + | **З приводу збереження легасі на рівні коду**: на даний момент, | ||
| + | |||
| + | <code php> | ||
| + | $userStates = [ | ||
| + | ' | ||
| + | ' | ||
| + | ]; | ||
| + | </ | ||
| + | |||
| + | І використовуйте старий і загалом зручний формат оголошення масивів у вигляді | ||
| + | |||
| + | <code php> | ||
| + | $userStates = array( | ||
| + | ' | ||
| + | ' | ||
| + | ); | ||
| + | </ | ||
| + | |||
| + | Ні, це не стосується використання автоінкрементних квадратних дужок при заповненні даних у масивах, | ||
| + | |||
| + | <code php> | ||
| + | $data[] = $userLink; | ||
| + | $data[] = $userAddress; | ||
| + | $data[] = $userCash; | ||
| + | </ | ||
| + | |||
| + | Також не використовуйте функціонал, | ||
| + | |||
| + | У разі, якщо вам потрібно змінити наявний код, що вже працює, | ||
| + | |||
| + | Якщо ви пишете щось поруч з існуючим кодом, що в основному повторює його функціональність, | ||
| + | |||
| + | ==== Коментування коду ==== | ||
| + | |||
| + | Коментування всіх функцій і методів - **суворо обов' | ||
| + | |||
| + | <code php> | ||
| + | |||
| + | /** | ||
| + | * Implementation of funeral services with graves management | ||
| + | */ | ||
| + | |||
| + | class UbillingFuneralServices { | ||
| + | |||
| + | /** | ||
| + | * Contains system alter config as key=> | ||
| + | * | ||
| + | * @var array | ||
| + | */ | ||
| + | protected $altCfg = array(); | ||
| + | |||
| + | /** | ||
| + | * Contains graves as id=> | ||
| + | * | ||
| + | * @var array | ||
| + | */ | ||
| + | protected $allGraves = array(); | ||
| + | |||
| + | /** | ||
| + | * System message helper placeholder | ||
| + | * | ||
| + | * @var object | ||
| + | */ | ||
| + | protected $messages = ''; | ||
| + | |||
| + | /** | ||
| + | * Default module URL | ||
| + | */ | ||
| + | const URL_ME = '? | ||
| + | |||
| + | /** | ||
| + | * Creates new funeral services instance | ||
| + | | ||
| + | * @return void | ||
| + | */ | ||
| + | public function __construct() { | ||
| + | $this-> | ||
| + | $this-> | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * Loads required system configs into protected properties for further usage | ||
| + | | ||
| + | * @global object $ubillingConfig | ||
| + | | ||
| + | * @return void | ||
| + | */ | ||
| + | protected function loadConfig() { | ||
| + | global $ubillingConfig; | ||
| + | $this-> | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * Inits system messages object | ||
| + | | ||
| + | * @return void | ||
| + | */ | ||
| + | protected function initMessages() { | ||
| + | $this-> | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * Returns current graves data from protected property | ||
| + | | ||
| + | * @return array | ||
| + | */ | ||
| + | public function getGraves() { | ||
| + | $result = $this-> | ||
| + | return ($result); | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * Sets some grave state | ||
| + | | ||
| + | * @param int $graveId | ||
| + | * @param array $graveData | ||
| + | | ||
| + | * @retrun void | ||
| + | */ | ||
| + | public function setGraves($graveId, | ||
| + | if ((isset($graveData[' | ||
| + | $this-> | ||
| + | } | ||
| + | } | ||
| + | |||
| + | /** | ||
| + | * Renders existing graves list | ||
| + | | ||
| + | * @return string | ||
| + | */ | ||
| + | public function renderGravesList() { | ||
| + | $result = ''; | ||
| + | if (!empty($this-> | ||
| + | $cells = wf_TableCell(__(' | ||
| + | $cells.= wf_TableCell(__(' | ||
| + | $cells.= wf_TableCell(__(' | ||
| + | $cells.= wf_TableCell(__(' | ||
| + | $rows = wf_TableRow($cells, | ||
| + | foreach ($this-> | ||
| + | //single string comment here | ||
| + | $cells = wf_TableCell($io); | ||
| + | $cells.= wf_TableCell($each[' | ||
| + | $cells.= wf_TableCell($each[' | ||
| + | $cells.= wf_TableCell($each[' | ||
| + | $rows.= wf_TableRow($cells, | ||
| + | } | ||
| + | $result.=wf_TableBody($rows, | ||
| + | } else { | ||
| + | $result.=$this-> | ||
| + | } | ||
| + | return ($result); | ||
| + | } | ||
| + | |||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | Правда ж, не складно написати кілька слів про те, що робить метод, що, якого типу і в якому вигляді лежить у змінній? | ||
| + | |||
| + | ===== Codeflow ===== | ||
| + | |||
| + | ==== Приклад у картинках ==== | ||
| + | {{ : | ||
| + | |||
| + | |||
| + | ==== Локалізація ==== | ||
| + | |||
| + | З огляду на те, що Ubilling використовується на території різних країн, де використовуються різні мови, подбайте про те, щоб ваш код можна було легко локалізувати. Тобто під час виведення будь-яких написів, | ||
| + | |||
| + | ==== Логування ==== | ||
| + | |||
| + | Під час запису подій у загальний системний лог, за допомогою log_register() або будь-якими іншими способами, | ||
| + | |||
| + | * (логін користувача) | ||
| + | * {логін адміністратора} | ||
| + | * < | ||
| + | * [цифровий ID чого-небудь] | ||
| + | * `якесь рядкове значення` | ||
| + | |||
| + | Хороший приклад: | ||
| + | <code php> | ||
| + | log_register(' | ||
| + | </ | ||
| + | |||
| + | або | ||
| + | |||
| + | <code php> | ||
| + | log_register(' | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | ==== Документування змін ==== | ||
| + | Якщо у вас є доступ до редагування цієї wiki - документуйте зміни внесені вами. Як мінімум варто додати відомості про те, що ви щось зробили в [[changelog|Чейнджлог]]. Кінцеві користувачі повинні знати, як змінитися їхнє життя в майбутньому. Зміни, які не видимі кінцевому користувачеві і ніяк не впливають на його життя, в принципі, | ||
| + | |||
| + | * Модуль " | ||
| + | * Модуль " | ||
| + | |||
| + | Обов' | ||
| + | |||
| + | * alter.ini: додано нову опцію CHAINSAW_ENABLED, | ||
| + | |||
| + | Також у разі додавання нової опції, ви маєте задокументувати її на сторінках, | ||
| + | |||
| + | У яких випадках, | ||
| + | |||
| + | Критерії дуже прості: | ||
| + | |||
| + | - Ваш модуль вимагає конфігурації, | ||
| + | - Управляється кількома опціями | ||
| + | - Працює в синергії з іншими модулями | ||
| + | - Вимагає якоїсь специфічної конфігурації | ||
| + | - Робить неочевидні сторонній людині штуки | ||
| + | |||
| + | Не обов' | ||
| + | |||
| + | ==== Великодки, | ||
| + | |||
| + | Вітаються. Будь-які. У будь-якому не уєбанському вигляді. | ||
| + | Ваш код - це продукт ваших взаємин зі всесвітом. І якщо він складається з відсилок до фільмів, | ||
| + | |||
| + | ==== А де ж Best Practices? ==== | ||
| + | Або практичні поради щодо вирішення типових завдань. Оскільки контенту дійсно багато ми винесемо його в [[bestpractices|окрему статтю]]. | ||
| + | |||
| + | ==== Контрибуція в Ubilling ==== | ||
| + | |||
| + | Будь ласка, якщо ви хочете зробити свій внесок у розвиток проекту, | ||
| + | |||
| + | ==== Оформлення Пуллреквестів ==== | ||
| + | |||
| + | Для початку Вам необхідно створити ФОРК проекту. | ||
| + | |||
| + | Для цього натисніть вгорі сторінки проекту кнопку **Fork**. | ||
| + | {{ : | ||
| + | |||
| + | Ця дія зробить копію вихідного коду з усіма гілками у ваш акаунт. Це нам знадобиться пізніше. | ||
| + | |||
| + | Далі на сервері виконайте такі дії: | ||
| + | |||
| + | <code bash> | ||
| + | git clone https:// | ||
| + | cd Ubilling | ||
| + | git remote add my-fork https:// | ||
| + | git checkout -b master-some-fix | ||
| + | vi CONTRIBUTING.md | ||
| + | git add CONTRIBUTING.md | ||
| + | git commit -m "I add some line to CONTRIBUTING" | ||
| + | git push -u my-fork master-some-fix | ||
| + | </ | ||
| + | |||
| + | Заходимо на сторінку вашого форка і бачимо, | ||
| + | {{ : | ||
| + | |||
| + | Після створення пулреквесту - [[https:// | ||
| + | Чекаємо, | ||
| + | Головне, | ||
| + | |||
| + | Далі повертаємося в гілку master офіційного проєкту й оновлюємо вже змерджений код: | ||
| + | <code bash> | ||
| + | git checkout master | ||
| + | git pull | ||
| + | </ | ||
| + | |||
| + | Тепер можна видалити гілку з вашого форка ( master-some-fix): | ||
| + | |||
| + | <code bash> | ||
| + | git push my-fork : | ||
| + | git branch -D master-some-fix | ||
| + | </ | ||