为什么有人会省略关闭标签?


373

我一直在阅读?>,在文件末尾使用PHP close标签是一种不好的做法。标头问题在以下情况下似乎无关紧要(这是迄今为止唯一的好参数):

现代版本的PHP在php.ini中设置了output_buffering标志。如果启用了输出缓冲,则可以在输出HTML之后设置HTTP标头和cookie,因为返回的代码不会立即发送到浏览器。

每本优秀实践书籍和Wiki均以该“规则”开头,但没有人提供充分的理由。 是否还有另一个很好的理由跳过结尾的PHP标记?


3
可能重复[为什么在一些脚本,他们省略结束PHP标签>?](stackoverflow.com/questions/3219383/...
戈登

@Christian-您的意思是使用output_buffering是惰性的,还是不使用?>则是惰性的?
El Yobo 2010年

4
@戈登-我不认为这是一个重复,OP知道表面上的原因,只是想知道它是否可以通过输出缓冲完全解决。
El Yobo 2010年

5
更好的问题是:为什么要包含close标签?代码是邪恶的。最好的代码是根本没有代码。如果可以解决问题而不是使用代码解决,那么这比拥有代码更好。在这种情况下,不需要解决任何问题。没有close标签,代码可以正常工作。
still_dreaming_1

19
哦,天哪,这不是标签战与太空圣战的地方,大声笑:)
Kevin Wheeler 2015年

Answers:


321

提前发送标头可能会产生深远的影响。以下是我眼中突然想到的其中一些:

  1. 尽管当前的PHP版本可能会缓冲输出,但是将要用于部署代码的实际生产服务器比任何开发或测试机器都重要得多。而且他们并不总是倾向于立即跟随最新的PHP趋势。

  2. 您可能会为莫名其妙的功能丧失感到头痛。假设您正在实现某种付款网关,并在付款处理器成功确认后将用户重定向到特定的URL。如果发生某种PHP错误,甚至是警告或行末多余,付款可能仍未处理,并且用户似乎仍未开票。这也是不必要的重定向是邪恶的原因之一,如果要使用重定向,则必须谨慎使用。

  3. 即使在最新版本中,您在Internet Explorer中也可能会出现“页面加载已取消”类型的错误。这是因为AJAX响应/ json包含不应该包含的内容,因为某些PHP文件中的行尾多余,就像我几天前遇到的那样。

  4. 如果您的应用程序中有一些文件下载,它们也可能因此中断。而且即使多年后,您也可能不会注意到它,因为下载的特定习惯取决于服务器,浏览器,文件的类型和内容(以及其他一些我不想让您感到厌烦的因素) 。

  5. 最后,包括SymfonyZend和Laravel 在内的许多PHP框架(在编码指南中没有提及,但遵循了诉讼)和PSR-2标准(项目2.2)都要求省略结束标记。PHP手册本身(12),WordPress的Drupal的和许多其他PHP软件我想,提醒这样做。如果您只是习惯遵循标准(并为您的代码设置PHP-CS-Fixer),则可以忽略此问题。否则,您将始终需要牢记该问题。

奖励:与这两个字符相关的一些陷阱(实际上是一个陷阱):

  1. 即使是某些知名的库,在之后也可能包含多余的行尾?>。例如Smarty,即使2. *和3. *分支的最新版本也有此功能。因此,一如既往,请注意第三方代码。额外的好处:用于删除不必要的PHP结尾的正则表达式:(\s*\?>\s*)$在所有包含PHP代码的文件中以空文本替换。

我以前使用Netbeans IDE在“查找和替换”对话框中查找标签的正则表达式略有不同:\?>(?s:.){0,10}\Z 简短说明:changeset.hr/blog/miscellaneous/catch-near-eof-with-regex
frnhr 2013年

@Cek,它将捕获任何字符,包括10个以下字符的代码(包括代码)?>:例如,它匹配-并且将?> Hello在-中删除<?php echo "test"; ?> Hello。我们只想清除关闭标签。
HalilÖzgür13年

6
更糟糕的是,当结束标记后面有空白时,带有PHP 5.4的Apache 2.4.6实际上会在我们的生产机器上隔离错误。我只是浪费了几个小时,直到我终于用strace缩小了bug的范围。这是apache抛出的错误:[core:notice] [pid 7842] AH00052: child pid 10218 exit signal Segmentation fault (11)
Artem Russakovskii 2014年

3
@INTPnerd哦,这个问题和大多数答案都涉及标题问题,因此我假设阅读此线程的任何人都会对此有所了解。在这里的许多答案中,潜在的问题和导致问题的实际原因是后面的空格?>,该空格(与任何输出一样)导致报头在其输出后立即发送。没有“ HTML标头”(不相关的HTML5 <header>标签除外)。
HalilÖzgür15年

2
无论全局修饰符是什么,它都应该起作用:\ s * \?> \ s * \ Z注意最后的'\ Z'。它确保当且仅当它是文件末尾的最后一个非空白时才捕获php结束标记。
Erutan409

122

您应该?>省略php结束标记()的原因是,以便程序员不会意外发送多余的换行符。

您不应该离开php结束标记的原因是因为它会导致php标记不平衡,并且任何有思想的程序员都可以记住不要添加多余的空格。

所以对于你的问题:

还有另一个很好的理由跳过结尾的php标签吗?

不,没有另一个很好的理由跳过结尾的php标签。

我将结束一些不干扰结束标记的参数:

  1. 人们总是能够犯错,无论他们多么聪明。坚持减少可能的错误数量的做法是一个好主意。

  2. PHP不是XML。PHP不需要遵循XMLs严格的标准即可编写和运行。如果缺少结束标记使您感到烦恼,则可以使用结束标记,这不是一种固定的规则。


2
> 任何有专心的程序员都可以记住不要添加多余的空格。甚至更好的是,任何有1/2想法的开发人员都可以向SVC添加一个预提交钩子,以便自动删除任何尾随空格:大惊小怪,没有困惑。
BryanH

6
@BryanH,直到您拥有绝对需要尾随空格的文件,但这非常罕见。
zzzzBov 2013年

1
你说的没错,当然。查看马里奥的答案,找到一些非常不错的选择。
BryanH 2013年

>“您不应该放弃php结束标记的原因是,它会导致php标记不平衡,任何有思想的程序员都记得不要添加多余的空格。” 在Windows上,也许。在类似UNIX的系统上,所有文件都以\ n结尾,程序会为您添加它。 编辑:啊哈!就像@mario在下面指出的那样,PHP实际上就是在吃东西。
安德里亚(Andrea)

2
更重要的是,即使是只有三分之二的头脑的程序员也是人,却忘记了某些东西。
塞巴斯蒂安·马赫

57

这是一个新手编码风格的建议,它的使用意图很好,并由手册提供了建议。

  • ?>但是,回避仅解决已发送的常见报头(原始输出,BOM,通知等)及其后续问题的一些问题。

  • 实际上,PHP包含一些魔术,可以在?>结束标记之后吞噬单个换行符。尽管这有历史性的问题,并使新人仍然容易受到笨拙的编辑的影响,并在之后毫无意识地在其他空白进行改组?>

  • 从风格上有些人希望能够查看<?php?>作为SGML标签/ XML处理指令,这意味着一个后关闭的记号的平衡一致性。(顺便说一句,对于依赖关系联合类包含有用,以取代效率低下的逐个文件自动加载。)

  • 有点不寻常的<?php是,该开口的特征是PHPs 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存根利用了它,或它的冗余组合,?>如图所示。

  • 同样,void也return;很少替换为include脚本,从而使任何?>带有尾随空格的无效。

  • 然后是各种各样的软/人造贴近标签变体;鲜为人知且很少使用,但通常每个注释掉的令牌:

    • 简单的间距// ? >可避免PHP的令牌生成器进行检测。

    • 或正则// ﹖﹥表达式可以掌握的精美Unicode替代品(U + FE56小问号,U + FE65小角度支架)。

    两者都对PHP毫无意义,但是可以在不了解PHP或不了解PHP的外部工具包中具有实际用途。再次cat想到连接脚本,其结果是// ? > <?php串联保留了前一个文件节。

因此,对于强制性的结束标记省略,存在上下文相关但实用的替代方法。

?>两种方式的手动保姆都不是很现代。总是有自动化的工具(即使只是sed / awk或regex-oneliners)。特别是:

phptags标签整理器

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

通常可将其用于--unclosephp标记第三方代码,或者仅解决任何(以及所有)实际的空白/ BOM问题:

  • phptags --warn --whitespace *.php

它还可以处理--long标签转换等,以实现运行时/配置的兼容性。


7
是的,直率和挑衅的用语吸引了反对派。根据我过去的读物,只要您不使用无法处理结束令牌的软件,就不用关闭结束令牌。除非您能真正证明省略关闭令牌是不好的事情,而且要做的很
菜鸟

2
@Pichan:我会允许的。但是我想您还不太了解这里所说的内容。躲避和避免是两回事。而一半解决的问题是蛇油建议的结果。
mario'7

6
@mario:这是新手编码风格的推荐。我不同意。整个Zend Framework省略了close标签。我认为这是一个非常个人的选择,我真的很想让我的<?php打开,而且我不会感到新手:)
Daniele Vrut

1
HTML呢?然后需要吗?例如<?php if($var): ?>Hello World<?php endif; ?>???我真的很好奇,因为没有特别提到。
WASasquatch

1
@WASasquatch是的。如果要在HTML和PHP模式之间切换,则无论如何都需要关闭令牌。(与此处的原始问题并不完全相关。)
mario 2015年

22

这不是标签...

但是,如果您有它,则可能会冒空白。

如果然后将其用作文档顶部的包含,则可能会在尝试发送HTTP标头之前最终插入空格(即内容),这是不允许的。


10
如果不是标签,那是什么?
danidacar 2010年

你能举个例子吗?也许我的php配置是whack,但我无法重现该问题。
danidacar 2010年

2
file1.php:<?php $i = 1; ?> 然后file2.php:<?php include 'file1.php'; header('Location: http://www.google.com');?>
Quentin 2010年

1
输出缓冲也有缺点。它在服务器上使用了更多的内存(因为所有输出必须存储在RAM中直到输出为止;不进行缓冲就直接输出)。它也曾经如此缓慢。在大多数情况下,这些都不是问题,但是无论如何我还是很懒,所以为什么不关闭结束标记呢?我使用的方法phpcs是确保每个文件都留有结束标记,然后我就不用担心输出缓冲了:)
El Yobo 2010年

1
@danip:如果已在php配置文件中设置了output_buffer标志,则无法重现此问题。
吉超

16

不让结束?>进入是非常有用的。

该文件对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 );

将。

有一次,您必须懒惰以确保安全


3
这就是为什么我用斜体表示安全。这样可以避免出现错误,因为错误可能导致您在结束之后浪费大量时间来占用不必要的空间?>安全在这里可能不是一个好词。无论如何,它并不能解决任何问题(对于我来说,防止发生故障的代码对我来说不是不好的代码,echo这里的代码可能是不好的代码),但是/并且它仍然有效。在这方面证明我是错误的。
Shikiryu 2010年

我没打败你,顺便说一句。但是我的观点与您的观点是一致的。它不能解决任何问题。我从未说过这是无效的,所以我不需要证明任何事情。
基督教徒2010年

1
Chouchenos,我敢打赌,您的意思是安全,而不是安全。恕我直言,这太过分了。带您回到第一广场。;-)毕竟您不是在说错话。甚至PHP开发指南也鼓励您这样做。实际上,例如,依赖于结束标记的遗漏要比输出缓冲好得多。后者就像将display_errors设置为off。纯作弊。而且您的应用很有可能无法移植。我确实认为,通常最好不要完全依赖输出缓冲。
maraspin 2010年

1
我不想质疑那些喜欢放在?>仅PHP文件末尾的人。但是您是否曾经需要调试一些由尾随空格引起的错误?同样,并非所有服务器的配置方式都相同,尤其是当您移至另一台主机时,捕获错误非常耗时。如果您只想?>
做就做

16

根据docs,由于以下原因,最好省略结束标记,如果它位于文件末尾:

如果文件是纯PHP代码,则最好在文件末尾省略PHP关闭标记。这样可以防止在PHP结束标记之后添加意外的空格或换行,这可能会导致不良影响,因为当程序员不打算在脚本中的该点发送任何输出时,PHP将开始输出缓冲。

PHP手册>语言参考>基本语法> PHP标记



9

好吧,有两种查看方式。

  1. PHP代码只不过是一组XML处理指令,因此任何带有.php扩展名的文件都不过是XML文件,而这种文件恰好是为PHP代码而解析的。
  2. PHP恰好恰恰为其open和close标签共享XML处理指令格式。基于此,具有.php扩展名的文件可以是有效的XML文件,但不必如此。

如果您相信第一种方法,那么所有PHP文件都需要结束符。忽略它们将创建一个无效的XML文件。再说一次,没有开始<?xml version="1.0" charset="latin-1" ?>声明,您将始终没有有效的XML文件...因此,这不是主要问题...

如果您相信第二种方法,那就为两种类型的.php文件打开了大门:

  • 仅包含代码的文件(例如,库文件)
  • 包含本机XML和代码的文件(例如,模板文件)

基于此,仅代码文件可以在没有结束?>标记的情况下结束。但是XML代码文件不能无休止地结束,?>因为它会使XML失效。

但是我知道你在想什么。您正在考虑这有什么用,您永远不会直接呈现PHP文件,因此谁在乎它是否是有效的XML。好吧,如果要设计模板就很重要。如果它是有效的XML / HTML,则正常的浏览器将不会显示PHP代码(将其视为注释)。因此,您可以模拟模板,而无需在其中运行PHP代码。

我并不是说这很重要。这只是我不太常表达的一种观点,所以有什么更好的分享方式...

就个人而言,我不会关闭库文件中的标签,但会在模板文件中关闭...我认为这是个人喜好(和编码准则),而不是任何困难...


1
这是完全错误的。PHP不会将这些标签转换为XML,因此不会产生任何不平衡。
Drachenkatze 2013年

7
@Felicitus:我猜您错过了说“我并不是说这很重要。只是我不经常表达这种观点,所以有什么更好的地方分享它……”这一点与PHP无关。将标签翻译成XML。这是关于在XML上下文(例如HTML或编辑器等)中解释文件时会发生什么……但是却错过了一点……
ircmaxell 2013年

7

除了已经说过的所有内容之外,我还要提出另一个原因,这对我们进行调试是一个巨大的痛苦。

当结束php标记后面有空白时,带有PHP 5.4的Apache 2.4.6实际上在我们的生产机器上存在分段错误。我只是浪费了几个小时,直到我终于用strace缩小了bug的范围。

这是Apache引发的错误:

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

6

“是否还有另一个很好的理由(除了标题问题以外)跳过结尾的php标签?”

生成二进制输出,CSV数据或其他非HTML输出时,您不希望无意中输出多余的空白字符。


1
我有一个客户抱怨,因为他们的XML解析器在开始时有多余的空白行时拒绝了我们的输出。更糟糕的是,这仅发生在七台服务器中的一台服务器上,并且在未修订的配置文件中的结束标记后加了一行。
埃斯瓦尔德

5

优点

缺点

结论

我要说的是,支持省略标记的参数看起来更强(有助于避免header()引起头疼,这是PHP / Zend的“推荐”)。我承认这不是我在语法一致性方面见过的最“美丽”的解决方案,但是还有什么更好的呢?


2

由于我的问题被标记为与此重复的问题,我认为可以出于某些原因而张贴为什么省略结束标记是?>可以的。

  • 使用完整的处理指令语法(<?php ... ?>),PHP源是有效的SGML文档,可以对SGML解析器进行解析和处理而不会出现问题。除其他限制外,它也可以是有效的XML / XHTML。

没有什么可以阻止您编写有效的XML / HTML / SGML代码。PHP文档意识到了这一点。摘抄:

注意:还请注意,如果要将PHP嵌入XML或XHTML中,则需要使用<?php?>标记以保持符合标准。

当然,PHP语法不是严格的SGML / XML / HTML,并且您创建的文档不是SGML / XML / HTML,就像您可以将HTML转换为XHTML来兼容XML一样。

  • 在某些时候,您可能希望连接源。cat source1.php source2.php如果您由于省略结束?>标记而导致不一致,那么这将不像简单地那样简单。

  • 如果没有?>它很难说,如果文件是PHP转义或PHP留下忽略模式(PI标签<?php可能已经打开与否)。如果您始终将文档置于PHP忽略模式,则生活会更轻松。就像使用格式正确的HTML文档相比,使用未关闭,嵌套错误的标签等文档进行处理一样。

  • 似乎有些编辑器,例如Dreamweaver,可能在PI处于打开状态时会遇到问题[1]


0

如果我正确理解该问题,则与输出缓冲有关,这可能对结束/结束标记产生影响。我不确定这是一个完全有效的问题。问题在于输出缓冲区并不意味着将所有内容发送到客户端之前就将其保留在内存中。这意味着其中一些内容是。

程序员可以有目的地刷新缓冲区或输出缓冲区,因此PHP中的输出缓冲区选项是否真的改变了结束标记如何影响编码?我认为事实并非如此。

也许这就是为什么大多数答案都回到个人风格和语法的原因。


0

php代码有2种可能的用法:

  1. PHP代码,例如类定义或函数定义
  2. 使用PHP作为模板语言(即在视图中)

在第一种情况下,结束标记完全没有用处,在这种情况下,我也想只看到1(一个)php打开标记,而没有(零)结束标记。这是一个好习惯,因为它可以使代码整洁,并使逻辑与表示分离。对于演示案例(2.),有人发现关闭所有标签(甚至是PHP处理过的标签)是很自然的,这会引起混淆,因为PHP实际上有2个单独的用例,不应混用:逻辑/演算和介绍

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.