nmk

Лекція 15 (2 години). Організація коду: поділ логіки та подання

План лекції

  1. Проблема “Спагетті-коду”: змішування PHP та HTML.
  2. Концепція архітектурного патерну MVC (Model-View-Controller).
  3. Використання require та include для ізоляції файлів.
  4. Практична шаблонізація: винесення дизайну у Views (Вигляди).

Перелік умовних скорочень

Вступ

До цього етапу ми писали код “в лоб” (шлях новачка). У кожному нашому файлі (наприклад, index.php) ми підключалися до бази даних, відразу ж писали SQL-запит на витягування завдань і нижче, у цьому ж файлі, відкривали теги <!DOCTYPE html>, де через цикли виводили ці завдання. Коли проєкт розростається до тисяч рядків, такий підхід перетворює скрипт на некерований “Спагетті-код”. Змінити дизайн меню стає неможливо без ризику зламати логіку бази даних. У цій лекції ми навчимось професійному розділенню: як зробити так, щоб логіка калькуляцій жила окремо від візуального відображення сторінки.


1. Проблема змішування PHP з HTML

Уявіть класичний файл index.php початківця:

<?php
// ТУТ БАЗА
$pdo = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$stmt = $pdo->query("SELECT * FROM users");
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);

// ТУТ ВАЛІДАЦІЯ
if (isset($_POST['name'])) {
    if (strlen($_POST['name']) < 3) echo "Помилка!";
}
?>
<!-- ТУТ ДИЗАЙН -->
<html>
<body>
    <h1>Користувачі</h1>
    <?php foreach($users as $u): ?>
        <p><?= $u['name'] ?></p>
    <?php endforeach; ?>
</body>
</html>

Чому це погано?

  1. Командна робота: Верстальник (Фронтенд-розробник) боїться відкривати цей файл, оскільки випадково може стерти життєво важливий рядок $pdo->query, намагаючись просто змінити колір заголовка <h1>.
  2. Підтримка: Якщо вам треба додати ще одну таблицю або складну математику, ваш файл index.php роздується до 500 рядків, де логіка перемішана з тегами <div>.
  3. Безпека: Змішування логіки та виведення часто призводить до того, що програміст випадково виводить повідомлення про помилку бази даних прямісінько в екран користувачу.

2. Основи патерну MVC (Model-View-Controller)

Щоб навести лад, світова спільнота інженерів домовилась розділяти будь-який застосунок на 3 незалежні шари. Цей підхід назвали MVC.

У межах поточного курсу ми не можемо одразу побудувати повноцінний ООП-фреймворк, але ми можемо застосувати Принцип MVC (Поділ інтересів) на базових інструментах PHP.

3. Використання require та include для ізоляції файлів

Щоб розділити наш єдиний файл на “Логіку” та “Шаблон”, ми використаємо дві команди PHP, які вміють “вклеювати” один файл усередину іншого:

  1. include 'view.php'; (Включити) Спробує завантажити файл view.php. Якщо файл не знайдено — видасть жовте попередження (Warning), але робота скрипта продовжиться. Використовується рідко, здебільшого для некритичних рекламних блоків чи віджетів.
  2. require 'view.php'; (Вимагати) Строга версія. Якщо файл не знайдено — генерується критична помилка (Fatal Error) і скрипт миттєво гине. Це ідеально для наших шаблонів та конфігів баз даних.

4. Практична шаблонізація: Відокремлюємо View

Давайте проведемо Рефакторинг (перепишемо архітектуру) нашого списку завдань згідно з філософією MVC.

Крок 1: Створення чистого шаблону (View)

Створіть папку views/ і в ній файл task_list.php. Сюди ми переносимо ТІЛЬКИ HTML. Цей файл не знає, звідки беруться завдання, він просто розраховує, що змінна $tasks вже існує в пам’яті.

views/task_list.php (Вигляд):

<!DOCTYPE html>
<html lang="uk">
  <body style="font-family: sans-serif;">
    <h1>Мої Завдання</h1>

    <ul class="task-list">
      <!-- Ми робимо лише рендеринг, жодних підключень до бази! -->
      <?php foreach($tasks as $t): ?>
      <li>
        <?= htmlspecialchars($t['title']) ?> (Статус: <?= $t['is_done'] ?
        'Виконано' : 'В процесі' ?>)
      </li>
      <?php endforeach; ?>
    </ul>
  </body>
</html>

Крок 2: Створення Контролера-обробника

Наш старий index.php тепер стає чистим Контролером. З нього назавжди зникають теги <html> і відтепер він містить виключно PHP логіку.

index.php (Контролер):

<?php
// 1. ПІДКЛЮЧЕННЯ (Частина Моделі)
require_once 'db.php';

// 2. БІЗНЕС-ЛОГІКА (Контролер просить Модель дати дані)
$stmt = $pdo->query("SELECT * FROM tasks ORDER BY id DESC");

// Формуємо масив $tasks.
// Увага: Змінна $tasks зараз оживає в оперативній пам'яті сервера!
$tasks = $stmt->fetchAll(PDO::FETCH_ASSOC);


// 3. ПЕРЕДАЧА ДАНИХ У ВИГЛЯД (Рендеринг)
// Скрипт зупиняється, "викликає" файл шаблону.
// Оскільки змінна $tasks була оголошена РЯДКОМ ВИЩЕ,
// файл task_list.php буде чудово її "бачити" і зможе перебрати в foreach!
require_once 'views/task_list.php';
?>

Що ми отримали?

Тепер, якщо ми хочемо найняти дизайнера для зміни кольору кнопок чи шрифту, ми кажемо йому: “Працюй тільки в папці views/. Основні файли (там де паролі від БД) не чіпай”. Якщо настав час оптимізувати SQL-запити — Backend-розробник відкриває свій index.php і спокійно пише логіку, не відволікаючись на сотні рядків <div> і <style>.

Це найпростіша і найважливіша еволюція мислення від “кодувальника” до “інженера-архітектора”.


Висновки

  1. Запис PHP-алгоритмів роботи з базами даних (SQL запити) і HTML-тегів розмітки сторінки в межах одного нескінченного файлу (Spaghetti Code) є антипатерном, який швидко робить проєкт неможливим для підтримки та командної взаємодії.
  2. Професійна архітектура будується на принципах Поділу інтересів (Separation of Concerns). Найпопулярнішим стандартом такого поділу у веб-програмуванні є патерн MVC (Модель, Вигляд, Контролер).
  3. Модель повинна містити тільки логіку даних (Базу), Вигляд (Шаблон) містить виключно візуальну HTML-частину і цикли відображення, а Контролер об’єднує їх: він просить дані у Моделі і передає їх як масиви всередину підключеного Вигляду.
  4. Технічним реалізатором концепції розділення в класичному PHP виступають мовні інструкції require або include. Вони дозволяють склеювати різні файли в один цілісний потік під час виконання, передаючи всі ініціалізовані змінні з контролера до шаблону.

Джерела

  1. Офіційний мануал require (англ.): https://www.php.net/manual/en/function.require.php
  2. Патерн MVC простыми словами: https://uk.wikipedia.org/wiki/Model-View-Controller

Запитання для самоперевірки

  1. Уявіть, що ви відкриваєте файл products.php на 800 рядків, де перемішані SQL-запити до кошика товарів, CSS-стилі, та HTML-розмітка заголовків. Вкажіть щонайменше дві критичні проблеми, з якими стикнеться ваша команда, якщо доведеться терміново змінити дизайн кнопок кошика, не поламавши бази даних? Назвіть термін цього хаосу.
  2. Прокоментуйте кожну з трьох складових акроніму MVC (Model, View, Controller). Який саме файл відповідає за підключення до Бази і збереження Завдання згідно з цією архітектурою, а який зобов’язаний бути абсолютно “чистим” від SQL і містити тільки <!DOCTYPE html>?
  3. Як Контролер (наприклад index.php), який успішно дістав масив користувачів з Бази Даних у змінну $users_list, може поділитися (передати) цими даними з окремим файлом дизайну (наприклад views/users.php)? Чому файл дизайну “бачить” цю змінну, хоча в ньому вона не оголошувалася?
  4. В чому полягає критична і фундаментальна різниця у поведінці інтерпретатора між викликами структур include 'shablon.php' та require 'shablon.php'? Які наслідки очікують користувача, якщо цей файл shablon.php був колись випадково видалений з сервера, в обох випадках технологій підключення?
  5. Більшість фахівців радять підключати Шаблон Виводу (require 'views/list.php';) виключно у самому кінці Контралера (найнижчим рядком). Чому підключати Вигляд перед виконанням запитів до Бази ($pdo->query) логічно неправильно і призведе до фатальних помилок при рендерингу $tasks всередині Шаблону?