Тут показані розбіжності між вибраною ревізією та поточною версією сторінки.
Порівняння попередніх версій Попередня ревізія | Попередня ревізія Наступна ревізія По сторонах наступні версії | ||
codingguidelines [2018/06/14 18:11] |
codingguidelines [2023/08/01 11:43] nightfly [Оформлення Пуллреквестів] |
||
---|---|---|---|
Рядок 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 і рефлекторно натискає **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++; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ==== Іменування класів та об' | ||
+ | |||
+ | Усе досить просто. Рекомендованим є 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 —set-upstream 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 | ||
+ | </ |