Структура приложения
Маленький сайт умещается в одном файле. Но когда страниц десятки, код нужно раскладывать по файлам и папкам так, чтобы каждую часть было легко найти. Почти все фреймворки устроены по одной схеме — разберём её на простом примере.
Примерам этого урока нужен веб-сервер и несколько файлов, поэтому здесь они не запускаются.
Подключение файлов
Код из другого файла подключает 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, часть кода лежит не на своём месте.