include vs require в PHP: разница, примеры и лучшие практики

include vs require в PHP: разница, примеры и лучшие практики

include vs require в PHP: разница, примеры и лучшие практики

Один из первых вопросов в PHP — как правильно подключать файлы. В ход идут четыре конструкции: include, require, include_once и require_once. Кажется просто, но у каждой — своя семантика, влияние на ошибки, производительность и безопасность.

Что делают include и require

Обе конструкции «вклеивают» PHP‑файл в текущий во время выполнения: код подключаемого файла компилируется и выполняется в той же области видимости, что и место вызова.

<?php
// basic.php
include 'header.php';
eccho 'Привет!'; // опечатка вызовет ошибку на этой строке
include 'footer.php';

Главное отличие — реакция на ошибку при отсутствии файла:

  • include — генерирует предупреждение (E_WARNING), скрипт продолжит работу;
  • require — генерирует фатальную ошибку (E_ERROR), выполнение прервётся.
  • Разница include vs require на примере

    <?php
    $file = 'config.php';
    
    include $file; // Если файла нет — предупреждение и скрипт продолжит выполняться
    echo "Дальше работаем...n";
    
    require $file; // Если файла нет — фатальная ошибка, скрипт остановится
    echo "Эта строка не выполнится, если файла нет";
    

    Практическое правило: критически важные зависимости (конфиг, автозагрузка, константы) подключайте через require, опциональные блоки (например, виджеты) — через include.

    include_once и require_once

    Варианты с суффиксом _once подключают файл только один раз за выполнение скрипта. Это удобно для файлов с объявлениями функций/классов, чтобы избежать «Cannot redeclare…».

    <?php
    require_once __DIR__ . '/vendor/autoload.php';
    require_once __DIR__ . '/config.php';
    include_once __DIR__ . '/helpers.php';
    

    Минус: _once стоит немного дороже обычного include/require из‑за проверки, подключался ли файл ранее. Не вызывайте *_once в циклах — вынесите в точку входа (bootstrap). В проектах с OPCache разница небольшая, но правило остаётся актуальным для чистоты архитектуры.

    Правильные пути: __DIR__ и относительные подключения

    Частая ошибка новичков — полагаться на «текущую рабочую директорию» (getcwd), которая меняется в зависимости от точки входа (CLI, фронт‑контроллер, крон). Безопаснее формировать абсолютные пути от директории файла, в котором вы пишете include/require:

    <?php
    // Надёжный способ
    require __DIR__ . '/config/config.php';
    
    // Если файл на уровень выше
    require dirname(__DIR__) . '/bootstrap.php';
    
    // Для глубокой структуры
    require realpath(__DIR__ . '/../app/Routes.php');
    

    Альтернатива — настраивать include_path (php.ini или set_include_path), но для начинающих проще и прозрачнее использовать __DIR__ и dirname().

    <?php
    // Пример с include_path (опционально)
    set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__ . '/lib');
    include 'Utils.php'; // теперь ищется в ./lib
    

    Можно ли «вернуть значение» из подключаемого файла?

    Да. Результат include/require — это значение, которое вернул подключаемый файл оператором return. Удобно для конфигов.

    <?php
    // config/db.php
    return [
      'dsn' => 'mysql:host=localhost;dbname=app;charset=utf8mb4',
      'user' => 'root',
      'pass' => 'secret',
    ];
    
    // index.php
    $db = require __DIR__ . '/config/db.php';
    $pdo = new PDO($db['dsn'], $db['user'], $db['pass']);
    

    Если файл ничего не вернул, include/require возвращает 1 при успехе и false при неудаче (для include).

    Область видимости: переменные «протекают»

    Подключаемый файл выполняется в текущей области видимости. Он видит локальные переменные вызывающего контекста и может их изменять, а его переменные станут доступны после include/require. Это удобно, но может привести к неожиданностям. Изолируйте подключение в функцию, когда нужно скрыть переменные.

    <?php
    // layout.php
    $title = 'Главная';
    $content = '<p>Добро пожаловать</p>';
    require __DIR__ . '/view.php'; // view.php увидит $title и $content
    
    // Изоляция операций рендеринга
    function render($tpl, array $vars = []) {
        extract($vars, EXTR_SKIP);
        require __DIR__ . '/views/' . $tpl . '.php';
    }
    render('home', ['title' => 'Дом', 'content' => '<p>Текст</p>']);
    

    Безопасность: никогда не подключайте то, что пришло от пользователя

    Главное правило — не подставляйте в include/require значения из GET/POST/COOKIE/файлов без строгой валидации. Используйте белый список маршрутов/шаблонов, а не «динамические пути». Обязательно держите allow_url_include = Off (по умолчанию так и есть).

    <?php
    // Плохо ❌
    $view = $_GET['view'] ?? 'home';
    require __DIR__ . "/views/{$view}.php"; // RFI/LFI уязвимость
    
    // Хорошо ✅ — белый список
    $views = [
      'home' => 'home.php',
      'about' => 'about.php',
    ];
    $view = $_GET['view'] ?? 'home';
    $file = $views[$view] ?? $views['home'];
    require __DIR__ . '/views/' . $file;
    

    Производительность и структура проекта

  • Не используйте *_once в циклах и часто вызываемых функциях — подключайте ключевые файлы один раз в bootstrap (public/index.php).
  • Включите и настройте OPCache в продакшене — он кэширует байткод и уменьшает накладные расходы на подключения.
  • Соберите «точки входа»: один файл окружения (require config.php), один автозагрузчик, один роутер — меньше include‑хаоса, проще отладка.
  • Частые ошибки и как их избежать

  • Header already sent — лишние пробелы/строки в подключаемом файле до <?php. Уберите BOM и пробелы.
  • Cannot redeclare function/class — дубль подключения. Примените require_once или пересмотрите архитектуру.
  • Файл не найден в кроне/CLI — относительные пути. Используйте __DIR__ или абсолютные пути от корня проекта.
  • Смешение слэшей на Windows/Linux — формируйте пути через DIRECTORY_SEPARATOR или просто используйте прямой слэш «/», который поддерживается PHP кроссплатформенно.
  • Мини‑шпаргалка выбора

  • require — обязательная зависимость, без неё выполнение невозможно.
  • include — необязательный блок (баннер, виджет, экспериментальная панель).
  • *_once — для деклараций (классы, функции), чтобы избежать повторного подключения.
  • Пути — через __DIR__/dirname(), не через относительные «на авось».
  • Безопасность — только белые списки и жёстко заданные пути.
  • Что дальше изучать

    Если хотите системно прокачать PHP и научиться строить проекты с нуля до продакшена, обратите внимание на практический курс: Пройти практический курс «PHP и MySQL с Нуля до Гуру 3.0». Много практики, современные подходы и поддержка.

    Теперь вы уверенно различаете include и require, понимаете, когда нужны варианты *_once, как правильно указывать пути и не попадать в ловушки безопасности. Этого уже достаточно, чтобы собирать аккуратную структуру проекта и избежать типичных багов новичков.

    Источник

    НЕТ КОММЕНТАРИЕВ

    Оставить комментарий