Зачем опускать тег закрытия?
Я продолжаю читать, что использовать тег закрытия PHP ?>
в конце файла - плохая практика. Проблема заголовка кажется неуместной в следующем контексте (и это пока единственный хороший аргумент):
Современные версии PHP устанавливают флаг output_buffering в php.ini Если буферизация вывода включена, вы можете установить заголовки HTTP и файлы cookie после вывода html, поскольку возвращаемый код не отправляется в браузер немедленно.
Каждая книга по хорошей практике и вики начинается с этого "правила", но никто не предлагает веских причин. Есть ли еще одна веская причина пропустить конечный тег php?
14 answers
Хотя я не могу вспомнить никакой другой причины, отправка заголовков раньше, чем обычно, может иметь далеко идущие последствия. Ниже приведены лишь некоторые из них, которые пришли мне в голову в данный момент:
В то время как в текущих версиях PHP может быть включена буферизация вывода, фактические производственные серверы, на которых вы будете развертывать свой код, гораздо важнее, чем любые машины разработки или тестирования. И они не всегда следуют последним тенденциям PHP немедленно.
У вас могут быть головные боли из-за необъяснимой потери функциональности . Допустим, вы внедряете какой-то платежный шлюз и перенаправляете пользователя на определенный URL-адрес после успешного подтверждения обработчиком платежей. Если произойдет какая-либо ошибка PHP, даже предупреждение или избыточное окончание строки, платеж может остаться необработанным, и пользователь все еще может показаться неоплаченным. Это также одна из причин, по которой ненужное перенаправление является злом, и если перенаправление должно использоваться, его следует использовать с осторожностью.
В Internet Explorer могут возникать ошибки типа "Загрузка страницы отменена", даже в самых последних версиях. Это связано с тем, что AJAX ответ/json include содержит что-то, чего он не должен содержать, из-за избыточных окончаний строк в некоторых файлах PHP, с чем я столкнулся несколько дней назад.
Если у вас есть некоторые загрузки файлов в вашем приложении, они тоже могут сломаться из-за этого. И вы можете этого не заметить, даже спустя годы, поскольку специфическая привычка к загрузке зависит от сервера, браузера, типа и содержимого файла (и, возможно, некоторых других факторов, с которыми я не хочу вас утомлять).
Наконец, многие фреймворки PHP, включая Symfony, Zend и Laravel (об этом нет упоминания в руководстве по кодированию , но оно соответствует требованиям) и стандарт PSR-2 (пункт 2.2) требуют пропуска закрывающего тега. Руководство по PHP сам по себе (1,2), Wordpress, Drupal и многие другие PHP-программы, я думаю, советуют это сделать. Если у вас просто войдет в привычку следовать стандарту (и настроить PHP-CS-Fixer для вашего кода), вы можете забыть об этой проблеме. В противном случае вам всегда нужно будет держать этот вопрос в уме.
Бонус: несколько ошибок (на самом деле в настоящее время одна), связанных с этими 2 персонажами:
- Даже некоторые известные библиотеки могут содержать лишнюю строку окончания после
?>
. Примером может служить Smarty, даже в самых последних версиях ветвей 2.* и 3.* это есть. Поэтому, как всегда, следите за кодом третьей стороны. Бонус в бонусе: Регулярное выражение для удаления ненужных окончаний PHP: замените(\s*\?>\s*)$
пустым текстом во всех файлах, содержащих код PHP.
Причина, по которой вы должны оставить закрывающий тег php (?>
), заключается в том, чтобы программист случайно не отправил дополнительные символы новой строки.
Причина, по которой вы не должны оставлять закрывающий тег php, заключается в том, что он вызывает дисбаланс в тегах php, и любой программист с половиной ума может помнить, что не следует добавлять дополнительные пробелы.
Итак, что касается вашего вопроса:
Есть ли еще одна веская причина пропустить конечный тег php?
Нет, нет еще одна веская причина пропустить окончательные теги php.
Я закончу некоторыми аргументами в пользу того, чтобы не беспокоиться о закрывающем теге:
Люди всегда способны ошибаться, какими бы умными они ни были. Придерживаться практики, которая уменьшает количество возможных ошибок, - это (ИМХО) хорошая идея.
PHP - это не XML. PHP не должен придерживаться строгих стандартов XMLs, чтобы быть хорошо написанным и функциональным. Если отсутствующий закрывающий тег вас раздражает, вам разрешено использовать закрывающий тег, это не является непреложным правилом, так или иначе.
Это рекомендация по стилю кодирования для новичков , исполненная благих намерений и рекомендованная руководством.
Однако отказ от
?>
решает только небольшую часть общих заголовков, уже отправленных, вызывает (необработанный вывод, Спецификация , уведомления и т. Д.) И их последующие проблемы.PHP на самом деле содержит некоторую магию, позволяющую уничтожать одиночные разрывы строк после закрывающего токена
?>
. Хотя это имеет историческую выпускает, и оставляет новичков все еще подверженными ошибочным редакторам и неосознанному перетасовыванию других пробелов после?>
.Стилистически некоторые разработчики предпочитают рассматривать
<?php
и?>
как инструкции по обработке тегов SGML/XML, подразумевая согласованность баланса завершающего маркера закрытия. (Который, кстати, полезен для класса объединения зависимостей, включает в себя замену неэффективной автоматической загрузки файла за файлом.)Несколько необычно, что открытие
<?php
характеризуется как PHPSshebang (и полностью выполнимо для binfmt_misc), тем самым подтверждая избыточность соответствующего закрывающего тега.Существует очевидное несоответствие между классическими руководствами по синтаксису PHP, предписывающими
?>\n
, и более недавними (PSR-2), согласующимися с пропуском.
(Для справки: структура Zend, постулирующая одно над другим, не подразумевает присущего ей превосходства. Это неправильное представление что эксперты были привлечены к/целевой аудитории громоздких API).SCMS и современные IDE предоставляют встроенные решения, в основном облегчающие уход за близкими тегами.
Отказ от любого использования тега ?>
close просто задерживает объяснение базового поведения обработки PHP и семантики языка, чтобы избежать нечастых проблем. Это практично по-прежнему для совместной разработки программного обеспечения из-за различий в уровне владения участники.
Закрыть варианты тегов
Обычный ?> закрывающий тег также известен как
T_CLOSE_TAG
, или, таким образом, "закрыть токен".-
Он включает в себя еще несколько воплощений, из-за магии PHPs поедание новой строки:
?>\ n ( Перевод строки Unix)
?>\ r ( Возврат каретки, классический MACs)
?>\ r\ n ( CR/LF, на DOS/Win)
PHP не поддерживает комбинированный разрыв строки в Юникоде НЕЛ ( U+0085), однако.
Ранние версии PHP имели компиляторы IIRC, несколько ограничивающие агностицизм платформы (FI даже просто использовал
>
в качестве маркера близости), что, вероятно, является историческим происхождением избегания закрытых тегов. Часто упускается из виду, но до PHP7 удаляет их, обычный
<?php
открывающий токен может быть действительным в паре с редко используемым</script>
как нечетный закрывающий знак.-
" жесткий тег закрытия" даже не один - просто придумал этот термин для аналогии. Концептуально и с точки зрения использования
__halt_compiler
однако должен быть распознан как маркер близости.__HALT_COMPILER(); ?>
, в котором в основном токенизатор отбрасывает любой код или простые разделы HTML после этого. В определенные заглушки PHAR используют это или его избыточную комбинацию с
?>
, как показано на рисунке. Аналогично делает пустым
return;
нечасто заменяйте сценарии включения, делая любые?>
с конечными пробелами неэффективными.-
Затем существуют всевозможные мягкие/искусственные варианты закрывающих тегов; менее известные и редко используемые, но обычно для закомментированных токенов:
Простой интервал
// ? >
чтобы избежать обнаружения токенизатором PHPS.Или необычные заменители Юникода
// ﹖﹥
( U+FE56 МАЛЕНЬКИЙ ВОПРОСИТЕЛЬНЫЙ ЗНАК, U+FE65 МАЛЕНЬКАЯ УГЛОВАЯ СКОБКА), которую может понять регулярное выражение.
Оба ничего не значат для PHP, но могут иметь практическое применение для неосведомленных или полуосознанных внешних наборов инструментов PHP. Снова
cat
- на ум приходят объединенные сценарии с результирующими// ? > <?php
конкатенациями, которые встроены - сохраняют прежний файл разделение.
Таким образом, существуют контекстно-зависимые, но практические альтернативы императивному пропуску закрывающего тега.
Ручная настройка ?>
закрывающих тегов в любом случае не очень современна. Для этого всегда существовали инструменты автоматизации (даже если это были только sed/awk или регулярные выражения). В частности:
Теги Phptags более аккуратные
https://fossil.include-once.org/phptags/
Который мог бы обычно используется для --unclose
тегов php для стороннего кода или, скорее, просто исправляет любые (и все) фактические проблемы с пробелами/спецификациями:
phptags --warn --whitespace *.php
Он также обрабатывает --long
преобразование тегов и т.д. для совместимости среды выполнения/конфигурации.
Это не тег...
Но если он у вас есть, вы рискуете получить пробел после него.
Если вы затем используете его в качестве включения в верхней части документа, вы можете в конечном итоге вставить пробелы (т. Е. Содержимое) перед попыткой отправки HTTP-заголовков... что запрещено.
Довольно полезно не допускать закрытия ?>
.
Файл остается действительным для PHP (не синтаксическая ошибка), и, как сказал @David Dorward, он позволяет избежать пробелов/разрывов (всего, что может отправить заголовок в браузер) после ?>
.
Например,
<?
header("Content-type: image/png");
$img = imagecreatetruecolor ( 10, 10);
imagepng ( $img);
?>
[space here]
[break line here]
Не будет действительным.
Но
<?
header("Content-type: image/png");
$img = imagecreatetruecolor ( 10, 10 );
imagepng ( $img );
Будет.
На этот раз вы должны быть ленивы, чтобы быть в безопасности.
Согласно документам , предпочтительнее опустить закрывающий тег, если он находится в конце файла по следующей причине:
Если файл представляет собой чистый PHP-код, предпочтительно опустить закрывающий тег PHP в конце файла. Это предотвращает случайное добавление пробелов или новых строк после закрывающего тега PHP, что может вызвать нежелательные эффекты, поскольку PHP начнет буферизацию вывода, когда программист не намерен отправлять какие-либо выходные данные в этот момент в сценарии.
Руководство по PHP > Справочник по языку > Базовый синтаксис > Теги PHP
Ну, есть два способа взглянуть на это.
- PHP-код - это не что иное, как набор инструкций по обработке XML, и поэтому любой файл с расширением
.php
- это не что иное, как XML-файл, который просто случайно анализируется для PHP-кода. - PHP просто так получилось, что он использует формат инструкций по обработке XML для своих тегов открытия и закрытия. Исходя из этого, файлы с расширениями
.php
МОГУТ быть допустимыми XML-файлами, но им не нужно быть.
Если вы верите первому маршруту, то все PHP-файлы требуют закрывающих конечных тегов. Если их опустить, будет создан недопустимый XML-файл. С другой стороны, без объявления открытия <?xml version="1.0" charset="latin-1" ?>
у вас все равно не будет действительного XML-файла... Так что это не главная проблема...
Если вы верите второму маршруту, который открывает дверь для двух типов файлов .php
:
- Файлы, содержащие только код (например, библиотечные файлы)
- Файлы, содержащие собственный XML, а также код (например, файлы шаблонов)
Исходя из этого, файлы только с кодом могут заканчиваться без закрывающего тега ?>
. Но файлы XML-кода не подходят для завершения без закрытия ?>
, так как это приведет к недействительности XML.
Но я знаю, о чем ты думаешь. Вы думаете, какое это имеет значение, вы никогда не будете отображать PHP-файл напрямую, так что кого волнует, является ли он допустимым XML. Ну, это имеет значение, если вы разрабатываете шаблон. Если это допустимый XML/HTML, обычный браузер просто не будет отобразите PHP-код (он рассматривается как комментарий). Таким образом, вы можете создать макет шаблона без необходимости запускать PHP-код в...
Я не говорю, что это важно. Это просто мнение, которое я не вижу выраженным слишком часто, так что где лучше поделиться им...
Лично я не закрываю теги в файлах библиотеки, но делаю это в файлах шаблонов... Я думаю, что это личное предпочтение (и руководство по кодированию), основанное больше всего на чем-либо сложном...
Ну, я знаю причину, но не могу ее показать:
Для файлов, содержащих только PHP-код, закрывающий тег (
?>
) никогда не разрешается. Это не требуется PHP, и его отсутствие предотвращает случайное добавление завершающего пробела в ответ.
Источник: http://framework.zend.com/manual/en/coding-standard.php-file-formatting.html
В дополнение ко всему, что уже было сказано, я собираюсь привести еще одну причину, по которой нам было очень трудно отлаживать.
Apache 2.4.6 с PHP 5.4 на самом деле ошибки сегментации на наших производственных машинах, когда за закрывающим тегом php
остается пустое пространство. Я просто потратил впустую часы, пока, наконец, не сузил круг поиска ошибки с помощью strace.
Вот ошибка, которую выдает Apache:
[core:notice] [pid 7842] AH00052: child pid 10218 exit signal Segmentation fault (11)
Плюсы
- Было бы логично закрыть любой открытый тег, как и в других языках. Не только теги X(HT)ML, но и фигурные скобки, скобки...
- Менее запутанный для начинающих.
Минусы
- Позволяет избежать головной боли при непреднамеренном добавлении пробелов после закрывающего тега, поскольку это нарушает поведение функции header()... Также известно, что некоторые редакторы или FTP-клиенты/серверы автоматически изменяют конец файлов (по крайней мере, это их конфигурация по умолчанию)
- Руководство по PHP говорит, что закрывающий тег необязателен, а Zend даже запрещает это.
Заключение
Я бы сказал, что аргументы в пользу исключения тега выглядят более убедительными (помогает избежать большой головной боли с заголовком () + это "рекомендация" PHP/Zend). Я признаю, что это не самое "красивое" решение, которое я когда-либо видел с точки зрения синтаксической согласованности, но что может быть лучше?
"Есть ли другая веская причина (кроме проблемы с заголовком) пропустить конечный тег php?"
Вы не хотите случайно выводить посторонние символы пробелов при создании двоичного вывода, CSV данных или других выходных данных, отличных от HTML.
Поскольку мой вопрос был помечен как дубликат этого, я думаю, что это нормально, чтобы опубликовать, почему НЕ по некоторым причинам может быть желательно опустить закрывающий тег ?>
.
- С полным синтаксисом Инструкций по Обработке (
<?php ... ?>
) PHP-источник является действительным документом SGML, который может быть проанализирован и обработан без проблем с помощью анализатора SGML. С дополнительными ограничениями он также может быть допустимым XML/XHTML.
Ничто не мешает вам писать допустимый код XML/HTML/SGML. PHP документация знает об этом. Выдержка:
Примечание: Также обратите внимание, что если вы внедряете PHP в XML или XHTML, вам нужно будет использовать теги , чтобы соответствовать стандартам.
Конечно, синтаксис PHP не является строгим SGML/XML/HTML, и вы создаете документ, который не является SGML/XML/HTML, точно так же, как вы можете превратить HTML в XHTML, чтобы быть совместимым с XML или нет.
В какой-то момент вам может потребоваться объединить источники. Это будет не так легко, как просто сделать
cat source1.php source2.php
, если у вас есть несоответствие, вызванное пропуском закрывающих тегов?>
.Без
?>
сложнее определить, был ли документ оставлен в режиме PHP escape или в режиме PHP ignore (возможно, тег PI<?php
был открыт или нет). Жизнь становится проще, если вы постоянно оставляете свои документы в режиме игнорирования PHP. Это похоже на работу с хорошо отформатированными HTML-документами по сравнению с документами с незакрытыми, плохо вложенными тегами и т.Д.Похоже, что некоторые редакторы как у Dreamweaver могут быть проблемы с PI, оставленным открытым [1].
Если я правильно понимаю вопрос, это связано с буферизацией вывода и влиянием, которое это может оказать на закрывающие/завершающие теги. Я не уверен, что это вполне обоснованный вопрос. Проблема в том, что выходной буфер не означает, что все содержимое хранится в памяти перед отправкой клиенту. Это означает, что часть контента есть.
Программист может намеренно очистить буфер или выходной буфер, так что опция выходного буфера в PHP действительно меняет способ закрытия тег влияет на кодирование? Я бы сказал, что это не так.
И, возможно, именно поэтому большинство ответов вернулось к личному стилю и синтаксису.
Существует 2 возможных варианта использования php-кода:
- PHP-код, такой как определение класса или определение функции
- Используйте PHP в качестве языка шаблонов (т.е. в представлениях)
В случае 1. закрывающий тег совершенно не подходит, также я хотел бы видеть только 1 (один) открытый тег php и НИ одного (нулевого) закрывающего тега в таком случае. Это хорошая практика, поскольку она делает код чистым и отделяет логику от представления. Для случая презентации (2.) некоторые сочли естественным закрыть все теги (даже обработанные PHP), что приводит к путанице, так как PHP фактически имеет 2 отдельных варианта использования, которые не следует смешивать: логика/исчисление и представление