Почему бы опустить закрывающий тег?

Я продолжаю читать, это плохая практика использовать закрывающий тег PHP ?> в конце файла. Проблема заголовка кажется неактуальной в следующем контексте (и пока это единственный хороший аргумент):

Современные версии PHP устанавливают флаг output_buffering в php.ini. Если включена выходная буферизация, вы можете установить HTTP-заголовки и куки-файлы после вывода HTML-кода, поскольку возвращаемый код не отправляется в браузер немедленно.

Каждая книга хорошей практики и вики начинаются с этого "правила", но никто не приводит веских причин.Есть ли еще одна веская причина пропустить конечный тег PHP?

14 ответов

Решение

Хотя я не могу вспомнить ни одной другой причины, отправка заголовков раньше обычного курса может иметь далеко идущие последствия. Ниже приведены лишь некоторые из них, которые пришли мне в голову в данный момент:

  1. Хотя в текущих версиях PHP может быть включена буферизация вывода, фактические рабочие серверы, на которых вы будете развертывать свой код, гораздо важнее, чем любые машины для разработки или тестирования. И они не всегда стремятся следовать последним тенденциям PHP сразу.

  2. У вас могут быть головные боли из-за необъяснимой потери функциональности. Скажем, вы реализуете какой-то платежный шлюз и перенаправляете пользователя на определенный URL после успешного подтверждения платежным процессором. Если произойдет какая-либо ошибка PHP, даже предупреждение или окончание лишней строки, платеж может остаться необработанным, а пользователю все равно может показаться, что счет не выставлен. Это также одна из причин, по которой ненужное перенаправление является злом, и если перенаправление должно использоваться, оно должно использоваться с осторожностью.

  3. Вы можете получить ошибки типа "Загрузка страницы отменена" в Internet Explorer, даже в самых последних версиях. Это связано с тем, что AJAX response / json include содержит что-то, чего не должно содержаться из-за лишних концов строк в некоторых файлах PHP, как я встречал несколько дней назад.

  4. Если у вас есть какие-то загрузки файлов в вашем приложении, они тоже могут сломаться из-за этого. И вы можете не заметить этого даже спустя годы, поскольку конкретная привычка к загрузке зависит от сервера, браузера, типа и содержимого файла (и, возможно, некоторых других факторов, с которыми я не хочу утомлять вас),

  5. Наконец, многие PHP-фреймворки, в том числе Symfony, Zend и Laravel (об этом нет упоминаний в руководствах по кодированию, но это следует их примеру) и стандарт PSR-2 (элемент 2.2), требуют пропуска закрывающего тега. Само руководство по PHP ( 1, 2), Wordpress, Drupal и многие другие программы PHP, я полагаю, советую сделать это. Если вы просто привыкли следовать стандарту (и устанавливаете PHP-CS-Fixer для своего кода), вы можете забыть об этом. В противном случае вам всегда нужно будет помнить о проблеме.

Бонус: несколько ошибок (на самом деле один), связанных с этими 2 персонажами:

  1. Даже некоторые известные библиотеки могут содержать лишние окончания строк после ?>, Например, Smarty, даже самые последние версии веток 2.* и 3.* имеют это. Так что, как всегда, следите за сторонним кодом. Бонус в бонусе: регулярное выражение для удаления ненужных окончаний PHP: заменить (\s*\?>\s*)$ с пустым текстом во всех файлах, которые содержат код PHP.

Причина, по которой вы должны оставить закрывающий тег php (?>) так, что программист случайно не отправляет дополнительные символы новой строки.

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

Итак, на ваш вопрос:

Есть ли еще одна веская причина пропустить заключительный тег php?

Нет, нет другой веской причины пропускать конечные теги php.

Я закончу с некоторыми аргументами, чтобы не беспокоиться с закрывающим тегом:

  1. Люди всегда могут совершать ошибки, независимо от того, насколько они умны. Придерживаться практики, которая уменьшает количество возможных ошибок, - (ИМХО) хорошая идея.

  2. PHP это не XML. PHP не должен придерживаться строгих стандартов XML, чтобы быть хорошо написанным и функциональным. Если отсутствующий закрывающий тег вас раздражает, вы можете использовать закрывающий тег, так или иначе, это не правило подстановки.

Это рекомендация для новичков в стиле кодирования, из лучших побуждений и рекомендаций руководства.

  • Отказавшись?> однако решает лишь небольшую часть общих отправленных ранее заголовков(необработанный вывод, спецификация, уведомления и т. д.) и их последующих проблем.

  • PHP на самом деле содержит немного магии, чтобы съесть отдельные разрывы строк после?>закрывающий токен Хотя это имеет исторические проблемы и оставляет новичков по-прежнему восприимчивыми к нестабильным редакторам и неосознанно перетасовывает их в другие пробелы после?>,

  • Стилистически некоторые разработчики предпочитают просматривать <?phpа также?> как теги SGML / инструкции по обработке XML, подразумевающие согласованность баланса в трейлинг-маркере закрытия. (Что, кстати,полезно для включения в класс, связанный с зависимостями, чтобы вытеснить неэффективную автозагрузку файлов.)

  • Несколько необычно открытие<?php характеризуется как PHP shebang(и полностью выполнимый для binfmt_misc), тем самым проверяя избыточность соответствующего закрытого тега.

  • Существует очевидное несоответствие между советами по классическому синтаксису PHP.?>\nи более поздние (PSR-2), согласившиеся с упущением.
    (Для справки: Zend Framework, постулирующий одно над другим, не подразумевает присущего ему превосходства. Это ошибочное мнение, что эксперты были привлечены к целевой аудитории громоздких API).

  • SCM и современные IDE предоставляют встроенные решения, в основном облегчающие работу с близкими тегами.

Не поощряя любое использование?>Тег close просто задерживает объяснение базового поведения PHP и семантики языка, чтобы избежать редких проблем. Это все ещепрактично для совместной разработки программного обеспечения из-за различий в квалификации участников.

Закрыть варианты тегов

  • Регулярный?> Закрыть тег также известен какT_CLOSE_TAGили, таким образом, "близкий токен".

  • Он включает в себя еще несколько воплощений из-за волшебнойеды новой строки PHP:

    ?> \ n(перевод строки Unix)

    ?> \ r(возврат каретки, классические MAC)

    ?>\ r \ n(CR / LF, в DOS/Win)

    Однако PHP не поддерживает перенос строки комиксов Unicode NEL(U + 0085).

    Ранние версии PHP имели компиляции IIRC, что несколько ограничивало платформенность (FI даже только что использовал>как близкий маркер), который является вероятным историческим источником избегания близких меток.

  • Часто упускают из виду, но до тех пор, пока PHP7 не удалит их, обычные<?phpвводный токен может бытькорректно соединен с редко используемым</script>какстранный закрывающий токен.

  • "Жесткий закрывающий тег" даже не один - просто придумал этот термин для аналогии. Концептуально и в использовании__halt_compilerоднако должен быть признан близким знаком.

    __HALT_COMPILER();
    ?>
    

    Который в основном имеет токенизатор, отбрасывающий любой код или простые разделы HTML после этого. В частности, заглушки PHAR используют это или их избыточную комбинацию с?>как изображено.

  • Аналогично делаетпустотуreturn;нечасто подставлять в скрипты include, рендеринг любого?>с замыкающими пробелами неэффективно.

  • Тогда есть все видымягких / искусственных вариаций меток закрытия; менее известные и редко используемые, но обычно позакомментированным токенам:

    • Простое расстояние// ? >чтобы избежать обнаружения токенайзером PHP.

    • Или модные заменители Юникода// ﹖﹥ (ОТМЕТКА МАЛОГО ВОПРОСА U+FE56, РЕШЕТКА МАЛОГО УГЛА U+FE65), который может понять регулярное выражение.

    Оба ничего не значат для PHP, но могут иметь практическое применение для неосознаваемых PHP или полуосознающих внешних инструментариев. Снова catобъединенные сценарии приходят на ум, в результате чего // ? > <?php конкатенации, которые inline-сохраняют прежнее разделение файла.

Таким образом, существуют контекстно-зависимые, но практические альтернативы упущению обязательного закрывающего тега.

Ручная няня ?> Закрыть теги не очень современно в любом случае. Для этого всегда были инструменты автоматизации (даже если это просто sed/awk или regex-oneliners). Особенно:

тег phptags более аккуратный

https://fossil.include-once.org/phptags/

Который обычно можно использовать для --unclose Теги php для стороннего кода, или, скорее, просто исправьте любые (и все) реальные проблемы с пробелами / спецификациями:

  • phptags --warn --whitespace *.php

Это также обрабатывает --long преобразование тегов и т. д. для совместимости во время выполнения / конфигурации.

Это не тег...

Но если он у вас есть, вы рискуете получить пробел после него.

Если вы затем используете его в качестве включения в верхней части документа, вы можете в конечном итоге вставить пробел (то есть содержимое), прежде чем пытаться отправить заголовки HTTP... что недопустимо.

Согласно документам, предпочтительно не указывать закрывающий тег, если он находится в конце файла по следующей причине:

Если файл представляет собой чистый код PHP, предпочтительно не указывать закрывающий тег PHP в конце файла. Это предотвращает случайные пробелы или новые строки, добавляемые после закрывающего тега PHP, что может вызвать нежелательные эффекты, потому что PHP начнет буферизацию вывода, когда программист не намерен отправлять какие-либо выходные данные в этот момент в сценарии.

Руководство по PHP> Справочник по языку> Основной синтаксис> Теги PHP

Это довольно полезно, чтобы не допустить закрытия ?> в.

Файл остается действительным для 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, и его пропуск предотвращает случайное внедрение конечного пробела в ответ.

Источник: http://framework.zend.com/manual/en/coding-standard.php-file-formatting.html

Ну, есть два способа взглянуть на это.

  1. PHP-код - это не более чем набор инструкций по обработке XML, и, следовательно, любой файл с .php Расширение - это не что иное, как XML-файл, который просто обрабатывается для PHP-кода.
  2. Так получилось, что PHP разделяет формат инструкций обработки XML для своих тегов open и close. Исходя из этого, файлы с .php Расширения МОГУТ быть действительными файлами XML, но они не должны быть.

Если вы верите первому маршруту, то все PHP-файлы требуют закрытия конечных тегов. Чтобы пропустить их, создаст недопустимый файл XML. Опять же, не имея открытия <?xml version="1.0" charset="latin-1" ?> декларация, у вас все равно не будет действительного XML-файла... Так что это не главная проблема...

Если вы верите второму маршруту, это открывает двери для двух типов .php файлы:

  • Файлы, содержащие только код (например, библиотечные файлы)
  • Файлы, которые содержат собственный XML, а также код (например, файлы шаблонов)

Исходя из этого, файлы только для кода можно завершить без закрытия ?> тег. Но файлы XML-кода не могут завершаться без закрытия ?> так как это сделает недействительным XML.

Но я знаю, о чем ты думаешь. Вы думаете, что это имеет значение, вы никогда не собираетесь визуализировать PHP-файл напрямую, поэтому кого волнует, является ли он действительным XML. Ну, это имеет значение, если вы разрабатываете шаблон. Если это допустимый XML/HTML, обычный браузер просто не будет отображать код PHP (он рассматривается как комментарий). Таким образом, вы можете макетировать шаблон без необходимости запуска кода PHP внутри...

Я не говорю, что это важно. Это просто мнение, которое я не вижу выраженным слишком часто, так что может быть лучше, чтобы поделиться этим...

Лично я не закрываю теги в файлах библиотеки, но делаю это в файлах шаблонов... Я думаю, что это личное предпочтение (и руководство по кодированию), основанное больше чем на чем-либо сложном...

В дополнение ко всему, что уже было сказано, я добавлю еще одну причину, из-за которой нам было очень трудно отлаживать.

Apache 2.4.6 с PHP 5.4 на самом деле дает сбой сегментации на наших производственных машинах, когда за закрытием есть свободное место php тег. Я просто потратил впустую часы, пока, наконец, не сузил ошибку с помощью strace.

Вот ошибка, которую выдает Apache:

[core:notice] [pid 7842] AH00052: child pid 10218 exit signal Segmentation fault (11)

"Есть ли еще одна веская причина (кроме проблемы с заголовком) пропустить заключительный тег php?"

Вы не хотите непреднамеренно выводить посторонние символы пробела при создании двоичного вывода, данных CSV или других выходных данных, отличных от HTML.

Pros

Cons

Заключение

Я бы сказал, что аргументы в пользу пропуска тега выглядят сильнее (помогает избежать большой головной боли с header() + это "рекомендация" PHP/Zend). Я признаю, что это не самое "красивое" решение, которое я когда-либо видел с точки зрения согласованности синтаксиса, но что может быть лучше?

Поскольку мой вопрос был помечен как дубликат этого вопроса, я думаю, что все в порядке, чтобы публиковать, почему НЕ опуская закрывающий тег ?> может быть по некоторым причинам желательно.

  • С полным синтаксисом инструкций по обработке (<?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 или в режиме игнорирования PHP (тег PI <?php возможно, был открыт или нет). Жизнь становится проще, если вы постоянно оставляете свои документы в режиме игнорирования PHP. Это похоже на работу с хорошо отформатированными документами HTML по сравнению с документами с закрытыми, плохо вложенными тегами и т. Д.

  • Похоже, что у некоторых редакторов, таких как Dreamweaver, могут быть проблемы с открытым PI [1].

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

Программист может преднамеренно очистить буфер или выходной буфер, поэтому действительно ли параметр выходного буфера в PHP изменит то, как закрывающий тег влияет на кодирование? Я бы сказал, что это не так.

И, возможно, именно поэтому большинство ответов вернулось к личному стилю и синтаксису.

Есть 2 варианта использования php кода:

  1. PHP-код, такой как определение класса или определение функции
  2. Использовать PHP в качестве языка шаблонов (т.е. в представлениях)

в случае 1. закрывающий тег совершенно не используется, также я хотел бы видеть только 1 (один) открытый тег php и NO (нулевой) закрывающий тег в таком случае. Это хорошая практика, поскольку она делает код чистым и отделяет логику от представления. Для случая представления (2.) некоторые обнаружили, что естественно закрыть все теги (даже обработанные PHP), что приводит к путанице, поскольку на самом деле PHP имеет два отдельных варианта использования, которые не должны смешиваться: логика / исчисление и презентация

Другие вопросы по тегам