Организация страниц в теме PHP: от основ до продвинутых техник

Раздел: Веб-разработка -> Веб-дизайн (шаблоны)

Основные подходы к реализации темы страницы

Наиболее эффективное решение:

Использование функций include или require с разделением на общие части (header, footer, sidebar) и буферизацией вывода для подстановки контента. Данный подход не требует внешних библиотек, легко масштабируется и понятен большинству разработчиков.

Структура файлов темы:


theme/
  index.php
  header.php
  footer.php
  page.php
  single.php
  sidebar.php

Theme php page (тема страницы на php)

В файле page.php подключаются header и footer, а основной контент формируется внутри. Для передачи данных используется массив, который извлекается через extract().


<?php
// page.php - шаблон страницы
$data = [
    'title' => 'Добро пожаловать',
    'content' => 'Это содержимое страницы.',
    'author' => 'Иван'
];
extract($data); // создаёт переменные $title, $content, $author
?>
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <title><?= $title ?></title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <?php include 'header.php'; ?>
    <main>
        <h2><?= $title ?></h2>
        <p><?= $content ?></p>
        <p class="author">Автор: <?= $author ?></p>
    </main>
    <?php include 'footer.php'; ?>
</body>
</html>

Типичные проблемы:

  • Конфликт имён переменных при использовании extract(). Рекомендуется передавать только необходимые данные и использовать префиксы.
  • Отсутствие проверки существования файла. Используйте file_exists() перед include.
  • Жёсткая привязка к конкретным файлам. Для гибкости применяйте условное подключение в зависимости от маршрута.

Цель подхода - создать минимальную, но расширяемую систему шаблонов для сайтов с небольшим количеством страниц. Подходит для личных проектов или прототипов.

Как организовать повторно используемые части шаблона через пользовательские функции?

Можно определить функции, которые подключают header, footer и другие блоки, принимая опциональные параметры. Пример реализации get_header() и get_footer():


<?php
// functions.php
function get_header($data = []) {
    extract($data);
    require 'header.php';
}

function get_footer($data = []) {
    extract($data);
    require 'footer.php';
}

function get_template_part($slug, $data = []) {
    $file = $slug . '.php';
    if (file_exists($file)) {
        extract($data);
        require $file;
    } else {
        echo "<p>Шаблон {$slug} не найден</p>";
    }
}
?>

Использование в page.php:


<?php
require 'functions.php';
$data = ['title' => 'Главная', 'content' => 'Контент...'];
?>
<!DOCTYPE html>
<html>
<head><title><?= $data['title'] ?></title></head>
<body>
    <?php get_header($data); ?>
    <?php get_template_part('content', $data); ?>
    <?php get_footer($data); ?>
</body>
</html>

Возможные сложности:

  • Глобальное состояние - переменные, переданные в функцию, не видны в подключаемом файле, если не использовать extract или передачу через ссылки. Решение: всегда явно передавать необходимые данные.
  • Конфликт с глобальной областью видимости. Для изоляции используйте замыкания или классы.

Подходит для средних проектов, где требуется единообразное подключение общих частей.

Как отделить логику от представления с помощью шаблонизатора Twig?

Twig - популярный шаблонизатор для PHP. Он позволяет использовать наследование, блоки, фильтры. Установка через Composer:


composer require twig/twig

Код загрузки и рендеринга шаблона:


<?php
require_once 'vendor/autoload.php';

$loader = new \Twig\Loader\FilesystemLoader('templates');
$twig = new \Twig\Environment($loader, [
    'cache' => 'cache',
    'debug' => true
]);

echo $twig->render('page.twig', [
    'title' => 'Мой сайт',
    'content' => 'Текст страницы'
]);
?>

Файл templates/page.twig:


<!DOCTYPE html>
<html>
<head>
    <title>{{ title }}</title>
</head>
<body>
    {% include 'header.twig' %}
    <main>
        <h2>{{ title }}</h2>
        <p>{{ content }}</p>
    </main>
    {% include 'footer.twig' %}
</body>
</html>

Ошибки при внедрении:

  • Забыли установить расширение mbstring или fileinfo - без них Twig может работать некорректно.
  • Неправильный путь к папке templates - проверяйте права доступа.
  • Использование auto_reload в продакшене снижает производительность; используйте кеш.

Цель - полное разделение PHP-логики и HTML. Рекомендуется для крупных проектов с командой дизайнеров.

Как сделать систему шаблонов более гибкой с помощью ООП?

Создание класса View, который загружает шаблон и передаёт данные. Пример:


<?php
class View {
    private $template;
    private $data;

    public function __construct($template, $data = []) {
        $this->template = $template;
        $this->data = $data;
    }

    public function render() {
        $file = __DIR__ . '/templates/' . $this->template . '.php';
        if (!file_exists($file)) {
            throw new Exception("Шаблон {$this->template} не найден");
        }
        extract($this->data);
        ob_start();
        include $file;
        return ob_get_clean();
    }

    public function renderPartial($partial, $partialData = []) {
        $partialView = new self($partial, array_merge($this->data, $partialData));
        return $partialView->render();
    }
}

// Использование
$view = new View('page', ['title' => 'О нас', 'content' => 'Текст...']);
echo $view->render();
?>

В шаблоне page.php можно вызвать renderPartial('header'):


<?php
/** @var View $this */
?>
<html>
<body>
    <?= $this->renderPartial('header') ?>
    <main>
        <h2><?= $this->data['title'] ?? '' ?></h2>
    </main>
    <?= $this->renderPartial('footer') ?>
</body>
</html>

Проблемы ООП-подхода:

  • Переусложнение для простых задач - используйте только при необходимости.
  • Сложность отладки из-за буферизации и наследования.
  • Необходимость документации и соблюдения единого интерфейса.

Подходит для фреймворков и крупных приложений, где важна тестируемость и расширяемость.

Расширенные примеры шаблонов страниц

Иерархия шаблонов как в WordPress

Реализация выбора шаблона в зависимости от типа запроса. Создаётся функция load_template(), которая проверяет наличие файлов по приоритету (single.php, page.php, index.php).

Пример

<?php
function load_template($type, $slug = '', $data = []) {
    $templates = [];
    if ($slug) {
        $templates[] = "{$type}-{$slug}.php";
    }
    $templates[] = "{$type}.php";
    $templates[] = 'index.php';

    foreach ($templates as $template) {
        if (file_exists($template)) {
            extract($data);
            require $template;
            return;
        }
    }
    echo 'Шаблон не найден';
}

// Пример для страницы с ID 42
load_template('page', '42', ['title' => 'Страница 42', 'content' => 'Контент']);
// Если page-42.php нет, загрузится page.php, иначе index.php

Результат: будет подключён первый найденный файл. Это позволяет создавать уникальные шаблоны для конкретных страниц.

(Страница отображается в зависимости от файла. Например, page-42.php может иметь особую вёрстку.)

Вложенные шаблоны с использованием буферизации (layout)

Создание базового layout, который содержит общую структуру, и дочерние шаблоны заполняют блоки.

Пример

<?php
// layout.php
?>
<!DOCTYPE html>
<html>
<head><title><?= $title ?></title></head>
<body>
    <header>Шапка</header>
    <main>
        <?= $content ?>
    </main>
    <footer>Подвал</footer>
</body>
</html>
Пример

<?php
// render.php - функция формирования контента в буфере
function render($view, $data = []) {
    ob_start();
    extract($data);
    include $view . '.php';
    return ob_get_clean();
}

$pageContent = render('about', ['text' => 'О компании']);
echo render('layout', ['title' => 'О нас', 'content' => $pageContent]);
?>

Результат: страница содержит обёртку layout с подставленным контентом из about.php.

Автоматическая загрузка шаблонов через маршрутизатор

Связывание URL с конкретным шаблоном с помощью простого роутера.

Пример

<?php
$requestUri = $_SERVER['REQUEST_URI'];
$path = parse_url($requestUri, PHP_URL_PATH);
$path = trim($path, '/');

$templateMap = [
    '' => 'home',
    'about' => 'page',
    'contact' => 'contact',
    'blog' => 'archive'
];

$templateName = $templateMap[$path] ?? '404';
if (file_exists($templateName . '.php')) {
    require $templateName . '.php';
} else {
    http_response_code(404);
    require '404.php';
}

Пример файла contact.php:

Пример

<?php
$title = 'Контакты';
?>
<h2><?= $title ?></h2>
<form>...</form>

Результат: запрос /contact открывает contact.php, /blog - archive.php.

Передача данных через класс контейнера (Dependency Injection)

Пример

<?php
class TemplateEngine {
    private $data = [];

    public function set($key, $value) {
        $this->data[$key] = $value;
    }

    public function render($template) {
        extract($this->data);
        ob_start();
        include $template . '.php';
        return ob_get_clean();
    }
}

$engine = new TemplateEngine();
$engine->set('title', 'Главная');
$engine->set('items', ['a', 'b', 'c']);
echo $engine->render('home');

Шаблон home.php получает переменные $title и $items напрямую.

Кеширование скомпилированных шаблонов

Пример

<?php
$cacheFile = 'cache/page_' . md5($template . serialize($data)) . '.html';
if (file_exists($cacheFile) && (time() - filemtime($cacheFile) < 3600)) {
    readfile($cacheFile);
    exit;
}

ob_start();
extract($data);
include $template . '.php';
$output = ob_get_clean();
file_put_contents($cacheFile, $output);
echo $output;

Это ускоряет загрузку страниц, не требующих динамического контента.

Тема страницы на PHP - comments

En
Theme php page (php)