Avatar ·

Почему в PHP рекомендуется опускать закрывающий тег `?>` в конце файла?

Всем привет! Я начинающий PHP-разработчик и недавно заметил, что во многих современных фреймворках (Laravel, Symfony) и в документации часто пишут, что закрывающий тег `?>` в конце PHP-файла нужно опускать. Честно говоря, я не совсем понимаю, зачем это делать. Ведь в учебниках по PHP всегда показывают полную конструкцию: ```php ``` Я попробовал убрать `?>` в своем проекте, и код все равно работал. Но меня мучает вопрос: а что может пойти не так, если я оставлю закрывающий тег? Вроде бы ничего страшного не происходит. Может быть, это просто какая-то прихоть опытных разработчиков? Но недавно я прочитал, что это связано с безопасностью и HTTP-заголовками. Якобы из-за случайного пробела или перевода строки после `?>` можно получить ошибку "headers already sent". У меня такое было пару раз, но я думал, что это из-за чего-то другого. Объясните, пожалуйста, на пальцах: в чем реальная проблема с закрывающим тегом? Когда его можно оставлять, а когда нужно обязательно убирать? И как это связано с безопасностью и отправкой заголовков? Буду благодарен за примеры кода, которые наглядно покажут разницу. **Пример моего кода, который вызывает ошибку:** ```php Тут случайно оказался пробел перед началом HTML ... ``` Этот код иногда выдает "Warning: Cannot modify header information". Может быть, дело именно в закрывающем теге? <<>>

Проблема: невидимые символы после закрывающего тега

Вы совершенно правы — дело именно в закрывающем теге. Когда PHP-интерпретатор встречает ?>, он считает, что PHP-код закончился, и всё, что идёт дальше (включая пробелы, переводы строк и даже обычный текст), отправляется в выходной буфер как есть. Если после ?> есть хотя бы один пробел или пустая строка, они становятся частью вывода. А функция header() требует, чтобы вывод ещё не начинался.

Как это работает на практике

Рассмотрим ваш пример:

<?php
header('Content-Type: text/html; charset=utf-8');
echo 'Привет!';
?>

<!DOCTYPE html>

После ?> идёт пустая строка (символ перевода строки). PHP отправляет этот перевод строки в буфер вывода. Когда вызывается header(), PHP уже начал вывод (пустая строка — это уже вывод), поэтому возникает ошибка "Cannot modify header information". Уберите ?> — и проблема исчезнет, потому что весь файл останется в режиме PHP, и header() будет вызван до любого вывода.

Безопасность: случайный вывод и утечка данных

Проблема не только в заголовках. Если после ?> окажется случайный пробел, табуляция или перевод строки, они попадут в HTTP-ответ. В большинстве случаев это безобидно, но бывают ситуации, когда это может привести к уязвимостям:

  • Утечка чувствительных данных — если в файле с конфигурацией (например, config.php) после закрывающего тега есть пробел, а файл подключается в начале страницы, этот пробел будет отправлен до начала сессии или куки.
  • Нарушение работы API — при возврате JSON или XML лишний пробел сделает ответ невалидным.
  • Проблемы с кешированием — некоторые прокси-серверы могут неправильно интерпретировать вывод.

Когда можно оставлять закрывающий тег?

Есть всего два легитимных случая:

  1. Файлы, которые содержат только PHP-код — никогда не оставляйте ?> в конце. Это стандарт PSR-2 и PSR-12, которого придерживаются все современные фреймворки.
  2. Файлы, которые смешивают PHP и HTML — например, шаблоны. Но даже в этом случае лучше использовать короткие блоки PHP и не ставить ?> в конце файла, если после него ничего нет.

Правильный подход

Всегда пишите PHP-файлы без закрывающего тега:

<?php
header('Content-Type: text/html; charset=utf-8');
echo 'Привет!';

// Весь остальной код
// Нет закрывающего тега

Если в файле есть HTML после PHP, используйте конструкцию с открывающим тегом в нужных местах:

<?php
$title = 'Моя страница';
?>
<!DOCTYPE html>
<html>
<head>
    <title><?= $title ?></title>
</head>
<body>
    <?php echo 'Привет!'; ?>
</body>
</html>
<!-- Закрывающего тега ?> в конце нет -->

Итог

Опуская ?>, вы:

  • Избавляетесь от риска случайного вывода пробелов и ошибок с заголовками
  • Следуете современным стандартам кодирования
  • Делаете код более безопасным и предсказуемым

Запомните простое правило: если файл заканчивается PHP-кодом — не ставьте ?>. Это спасёт вас от многих часов отладки.

<<>>

Альтернативный взгляд: проблема с автозагрузкой и include

Помимо проблем с заголовками, есть ещё один важный аспект — работа с автозагрузкой классов и функций include/require.

Представьте, что у вас есть файл config.php:

<?php
return [
    'db_host' => 'localhost',
    'db_user' => 'root',
];
?>
(пробел после закрывающего тега)

Если вы подключаете его через $config = require 'config.php';, то из-за пробела после ?> возвращаемое значение будет не массивом, а строкой "1" (так как require возвращает 1 при успехе), а массив будет выведен как текст. В итоге $config станет 1, а не массивом с настройками.

Ещё хуже ситуация с классами. Если в файле класса после ?> есть пробел, а затем вызывается new SomeClass(), PHP может выдать фатальную ошибку "Class not found", потому что вывод пробела нарушил работу автозагрузчика.

Поэтому современные PHP-стандарты (PSR-4) требуют, чтобы файлы классов вообще не содержали закрывающего тега. Это гарантирует, что автозагрузка будет работать без сюрпризов.

Рекомендация: настройте свой редактор кода (PhpStorm, VS Code) так, чтобы он автоматически удалял пустые строки в конце файла и не добавлял закрывающий тег. Это избавит вас от 99% проблем.