Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Структура приложения

Маленький сайт умещается в одном файле. Но когда страниц десятки, код нужно раскладывать по файлам и папкам так, чтобы каждую часть было легко найти. Почти все фреймворки устроены по одной схеме — разберём её на простом примере.

Примерам этого урока нужен веб-сервер и несколько файлов, поэтому здесь они не запускаются.

Подключение файлов

Код из другого файла подключает require. Если файла нет, программа остановится с ошибкой:

<?php
// index.php
 
require __DIR__ . '/functions.php';
 
echo formatPrice(250);

require_once подключает файл только один раз, даже если строка встретится повторно. Есть ещё include — он при отсутствии файла лишь выдаёт предупреждение, поэтому для кода используют require.

Точка входа

В старых сайтах у каждой страницы был свой файл: about.php, contacts.php. Сейчас все запросы направляют в один файл — точку входа. Он лежит в папке public, а остальной код — выше, куда браузеру нет доступа:

project/
  public/
    index.php      — точка входа
  src/
    Controllers/   — обработчики запросов
    Models/        — работа с данными
  views/           — шаблоны страниц
  vendor/          — библиотеки Composer

Так посетитель не сможет открыть файл с настройками или классами напрямую.

Маршрутизатор

Точка входа смотрит на адрес и решает, какой код вызвать:

<?php
// public/index.php
 
require __DIR__ . '/../vendor/autoload.php';
 
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
 
$routes = [
    '/' => [App\Controllers\HomeController::class, 'index'],
    '/posts' => [App\Controllers\PostController::class, 'index'],
];
 
if (!isset($routes[$path])) {
    http_response_code(404);
    exit('Страница не найдена');
}
 
[$class, $method] = $routes[$path];
echo (new $class())->$method();

Соответствие «адрес — обработчик» называют маршрутом.

Контроллер

Контроллер принимает запрос, получает данные и передаёт их в шаблон:

<?php
// src/Controllers/PostController.php
 
namespace App\Controllers;
 
use App\Models\Post;
 
class PostController
{
    public function index(): string
    {
        $posts = Post::all();
 
        return render('posts/index', ['posts' => $posts]);
    }
}

Сам контроллер не содержит ни SQL-запросов, ни HTML.

Модель

Модель отвечает за данные: знает, как их получить и сохранить.

<?php
// src/Models/Post.php
 
namespace App\Models;
 
class Post
{
    public static function all(): array
    {
        return database()->query('SELECT id, title FROM posts ORDER BY id DESC')->fetchAll();
    }
}

Шаблон

Шаблон — это HTML с небольшими вставками PHP для вывода данных:

<?php
// views/posts/index.php
?>
<h1>Статьи</h1>
<ul>
    <?php foreach ($posts as $post): ?>
        <li><?= htmlspecialchars($post['title']) ?></li>
    <?php endforeach; ?>
</ul>

Запись <?= ... ?> — короткая форма echo. В шаблонах используют альтернативный синтаксис циклов с двоеточием и endforeach: он лучше читается среди HTML.

Модель, шаблон, контроллер

Такое разделение называют MVC — Model, View, Controller. Каждая часть меняется независимо: дизайнер правит шаблон, не трогая запросы, а смена базы данных не затрагивает страницы.

Частая ошибка

Не смешивайте всё в одном файле: запрос к базе, проверку формы и HTML вперемешку. Такой код невозможно ни проверить, ни использовать повторно. Если в шаблоне появляется SQL, а в модели — HTML, часть кода лежит не на своём месте.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.