为什么要省略关闭标签?

Why would one omit the close tag?

提问人:johnlemon 提问时间:12/11/2010 最后编辑:Mehranjohnlemon 更新时间:7/25/2019 访问量:131019

问:

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

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

每本好的实践书和维基都以这个“规则”开头,但没有人提供充分的理由。有没有其他很好的理由跳过结束的PHP标签?

PHP 安全 http-headers

评论

3赞 Gordon 12/11/2010
[为什么在某些脚本中他们省略了结束 php 标签?> ](stackoverflow.com/questions/3219383/...)
0赞 El Yobo 12/12/2010
@Christian - 你的意思是使用output_buffering是懒惰,还是省略懒惰??>
4赞 El Yobo 12/12/2010
@Gordon - 我不认为这是一个骗局,OP 知道表面上的原因,只是想知道它是否通过输出缓冲完全解决。
6赞 still_dreaming_1 2/15/2015
一个更好的问题是:为什么要包含关闭标签?代码是邪恶的。最好的代码是完全没有代码。如果一个问题可以消除而不是用代码来解决,这比有代码要好。在这种情况下,不需要解决任何问题。该代码在没有 close 标记的情况下工作正常。
20赞 Kevin Wheeler 8/14/2015
哦,上帝,这不是标签与空间圣战的地方,哈哈:)

答:

25赞 Quentin 12/11/2010 #1

它不是一个标签......

但是,如果你拥有它,你就有可能在它后面有空格。

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

评论

10赞 johnlemon 12/11/2010
如果它不是标签,它是什么?
0赞 johnlemon 12/11/2010
你能举个例子吗?也许我的 php 配置很糟糕,但我无法重现这个问题。
2赞 Quentin 12/11/2010
file1.php:然后file2.php:<?php $i = 1; ?> <?php include 'file1.php'; header('Location: http://www.google.com');?>
1赞 El Yobo 12/12/2010
输出缓冲也有缺点;它在服务器上使用更多的内存(因为所有输出都必须存储在RAM中,直到它被输出;没有缓冲,它就会直接消失)。它的速度也稍微慢了一点。在大多数情况下,这些都不是问题,但无论如何我都很懒,那么为什么不直接关闭结束标签呢?我用来确保我的每个文件都留下结束标记,然后我就不用担心输出缓冲:)phpcs
1赞 Jichao 3/14/2012
@danip:如果您在 php 配置文件中设置了 output_buffer 标志,则无法重现此问题。
10赞 tawfekov 12/11/2010 #2

好吧,我知道原因,但我无法表现出来:

对于仅包含 PHP 代码的文件,结束标记 () 从不 允许。PHP不需要它, 省略它会阻止 意外注入拖曳白色 空间进入响应。?>

来源:http://framework.zend.com/manual/en/coding-standard.php-file-formatting.html

评论

24赞 Matt Huggins 12/11/2010
“never allowed”这个标签可能是 Zend 的编码标准,但它不是 PHP 文件格式的语法规则。
16赞 Shikiryu 12/11/2010 #3

不让关闭非常有用。?>

该文件对 PHP 保持有效(不是语法错误),正如 Dorward 所说@David它允许避免在 .?>

例如

<?
    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赞 Shikiryu 12/13/2010
这就是为什么我把安全放在斜体上。它可以防止您出现错误,这些错误可能会花费您大量时间在 .安全在这里可能不是一个好词。无论如何,它没有解决任何问题(对我来说,防止事情发生并不是坏代码,这里本来是一个坏代码)但是/而且它仍然有效。证明我错了。?>echo
0赞 Christian 12/18/2010
顺便说一句,我没有对你投反对票。但我的观点与你的观点相符。它不能解决任何问题。我从来没有说过它无效,所以我不需要证明任何事情。
1赞 maraspin 12/18/2010
Chouchenos,我敢打赌你的意思是安全,而不是安全。恕我直言,这太过分了。把你带回原点。;-)毕竟你没有说错话。甚至PHP开发指南也鼓励你这样做。例如,实际上,依靠关闭标签省略而不是输出缓冲要好得多。后者就像把display_errors关掉。 纯粹的作弊。而且您的应用程序很有可能不便携。我真的认为,作为一项规则,最好不要依赖输出缓冲。
1赞 CoffeDeveloper 2/26/2015
我不想质疑那些喜欢放在 php 文件末尾的人。但是你有没有需要调试一些由尾随空格引起的错误?此外,并非所有服务器的配置方式都相同,尤其是当您移动到另一台主机时,捕获该错误非常耗时。如果你想放,就去做吧,如果你还添加了一些尾随空间,你的团队需要调试,准备好归咎于 git ^^?>?>
127赞 zzzzBov 12/16/2010 #4

您应该省略 php 结束标签 () 的原因是为了让程序员不会意外发送额外的换行符。?>

你不应该省略 php 结束标签的原因是因为它会导致 php 标签的不平衡,任何有一半想法的程序员都可以记住不要添加额外的空格。

所以对于你的问题:

有没有其他很好的理由跳过结尾的 php 标签?

不,没有其他很好的理由跳过结尾的 php 标签。

最后,我将提出一些不打扰结束标签的论据:

  1. 人们总是会犯错误,无论他们多么聪明。 坚持减少可能错误数量的做法(恕我直言)是个好主意。

  2. PHP 不是 XML。PHP 不需要遵守 XML 的严格标准才能写得好且功能强大。如果缺少的结束标签让您感到恼火,您可以使用结束标签,这不是一个一成不变的规则。

评论

3赞 BryanH 12/12/2012
> 任何有一半头脑的程序员都可以记住不要添加额外的空格。更好的是,任何有 1/2 头脑的开发人员都可以向 SVC 添加一个提交前的钩子,以便自动删除任何尾随空格:没有大惊小怪,没有麻烦。
6赞 zzzzBov 1/3/2013
@BryanH,直到你有一个绝对需要尾随空格的文件,但这种情况非常罕见。
1赞 BryanH 1/4/2013
当然,你是对的。查看马里奥的答案,了解一些非常酷的替代品。
0赞 mystery 10/18/2014
>“你不应该省略 php 结束标签的原因是因为它会导致 php 标签的不平衡,任何有一半头脑的程序员都可以记住不要添加额外的空格。”在 Windows 上,也许吧。在类 UNIX 系统上,所有文件都以 \n 结尾,程序会为您添加它。编辑:啊哈!正如下面 @mario 所指出的,PHP 实际上就是这样吃的。
2赞 Sebastian Mach 1/11/2016
更重要的是,即使是拥有三倍头脑的程序员也是人,会忘记一些事情。
9赞 ircmaxell 12/16/2010 #5

嗯,有两种看待它的方式。

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

如果您相信第一种路由,那么所有 PHP 文件都需要结束标记。省略它们将创建一个无效的 XML 文件。话又说回来,如果没有打开声明,你无论如何都不会有一个有效的XML文件......所以这不是一个大问题......<?xml version="1.0" charset="latin-1" ?>

如果您相信第二种途径,这将为两种类型的文件打开大门:.php

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

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

但我知道你在想什么。你在想这有什么关系,你永远不会直接渲染一个PHP文件,所以谁在乎它是否是有效的XML。好吧,如果您正在设计模板,这确实很重要。如果它是有效的 XML/HTML,普通浏览器将根本不显示 PHP 代码(它被视为注释)。因此,您可以模拟模板,而无需在其中运行PHP代码。

我并不是说这很重要。这只是一个我不经常看到表达的观点,所以还有什么更好的地方来分享它......

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

评论

1赞 Drachenkatze 10/23/2013
这是完全错误的。PHP 不会将这些标签转换为 XML,因此不会产生不平衡。
7赞 ircmaxell 10/23/2013
@Felicitus:我猜你错过了说“我不是说这很重要。这只是一个我不经常看到表达的观点,所以还有什么更好的地方来分享它......“ 这与PHP将标签转换为XML无关。这是关于在XML上下文(如HTML或编辑器等)中解释文件时会发生什么......但是错过了一点......
0赞 Niki Romagnoli 3/22/2021
PHP 和 XML 之间唯一的相似之处是尖括号。恕我直言,这个答案感觉比有用的更具误导性。
63赞 mario 12/17/2010 #6

这是一个新手编码风格的建议,用心良苦,并由手册建议。

  • 然而,避免只解决了已经发送的常见标头原因(原始输出、BOM、通知等)及其后续问题的一小部分?>

  • PHP实际上包含一些魔力,可以在关闭令牌之后吃掉单个换行符。尽管这存在历史问题,并且使新人仍然容易受到不稳定的编辑的影响,并在之后不知不觉地在其他空白中洗牌。?>?>

  • 从风格上讲,一些开发人员更喜欢查看 和 作为 SGML 标签/XML 处理指令,这意味着尾随收盘标记的余额一致性。(顺便说一句,对于依赖连接类来说很有,可以取代低效的逐个文件自动加载。<?php?>

  • 有点罕见的是,开口被描述为 PHPs shebang(并且完全可行,每binfmt_misc),从而验证了相应关闭标签的冗余。<?php

  • 在经典的PHP语法指南和最近的PHP语法指南PSR-2)之间有一个明显的建议差异。
    (郑重声明:Zend Framework 假设一个优于另一个并不意味着它固有的优越性。这是一种误解,认为专家被笨拙的 API 所吸引/目标受众)。
    ?>\n

  • SCM 和现代 IDE 提供了内置解决方案,主要缓解了密切标签的看护。

劝阻任何关闭标签的使用只会延迟解释基本的 PHP 处理行为和语言语义,以避免不常见的问题。由于参与者的熟练程度差异,协作软件开发仍然是实用的。?>

关闭标签变体

  • 常规关闭标记也称为 T_CLOSE_TAG,或因此称为“关闭标记”。?>

  • 它包含更多的化身,因为 PHP 的神奇换行符饮食

    ?>\n(Unix 换行)

    ?>\r(回车,经典 MAC)

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

    但是,PHP 不支持 Unicode 组合换行符 (U+0085)。NEL

    早期的PHP版本有IIRC编译,在一定程度上限制了平台不可知论(FI甚至只是用作关闭标记),这可能是关闭标记避免的历史起源。>

  • 经常被忽视,但在 PHP7 删除它们之前,常规的开局代币可以与很少用作奇数的收盘代币有效配对。<?php</script>

  • 硬关闭标签”甚至不是一个 - 只是为了类比而编造了这个术语。然而,从概念和用法上讲,__halt_compiler应该被认为是接近的标记。

    __HALT_COMPILER();
    ?>
    

    这基本上让分词器此后丢弃任何代码或纯 HTML 部分。特别是,PHAR 存根利用了它,或者它与所描述的冗余组合。?>

  • void 返回也是如此;很少在包含脚本中替换,使任何带有尾随空格的脚本无效。?>

  • 然后是各种软/假关闭标签变体;鲜为人知且很少使用,但通常每个注释掉的标记:

    • 简单的间距,以逃避PHP分词器的检测。// ? >

    • 或者花哨的 Unicode 替代品(U+FE56 小问号,U+FE65 小尖括号),正则表达式可以掌握。// ﹖﹥

    两者对PHP来说都毫无意义,但对于PHP无感知或半感知的外部工具包来说,它们都有实际用途。再次联接脚本浮现在脑海中,其生成的串联将内联保留以前的文件部分。cat// ? > <?php

因此,对于命令式关闭标签省略,有一些依赖于上下文但实用的替代方法。

无论哪种方式,贴标签的手动保姆都不是很现代。一直有自动化工具(即使只是 sed/awk 或正则表达式)。特别:?>

phptags 标记 tidier

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

这通常可用于第三方代码的php标签,或者更确切地说,只是修复任何(和所有)实际的空格/ BOM问题:--unclose

  • phptags --warn --whitespace *.php

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

评论

8赞 jpeltoniemi 7/8/2012
是的,直言不讳和挑衅性的措辞会吸引反对票。从我随着时间的推移所读到的内容来看,只要您不使用无法处理的软件,省略关闭令牌绝对没有缺点。除非你真的能证明省略关闭代币是不好的,而且是一件非常菜鸟的事情,否则我的反对票仍然;)
2赞 mario 7/8/2012
@Pichan:我允许。但我想你还没有完全理解这里所说的内容。回避和回避是两回事。而解决一半的问题是蛇油建议的结果。
6赞 Daniele Vrut 10/18/2013
@mario:这是一个新手编码风格推荐。我不同意。整个 Zend Framework 省略了关闭标签。我认为这是一个非常个人的选择,我真的更喜欢打开我的 <?php,我不觉得自己是新手:)
1赞 WASasquatch 1/20/2015
HTML呢?那么需要吗?对于考试???我真的很好奇,因为它没有特别提到。<?php if($var): ?>Hello World<?php endif; ?>
1赞 mario 1/20/2015
@WASasquatch 是的。如果你在HTML和PHP模式之间切换,那么在任何情况下你都需要关闭标记。(与这里的原始问题并不真正相关。
0赞 Ruz 12/18/2010 #7

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

程序员可以故意刷新缓冲区或输出缓冲区,那么 PHP 中的输出缓冲区选项真的会改变结束标签对编码的影响吗?我认为事实并非如此。

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

343赞 Halil Özgür 12/21/2010 #8

在正常课程之前发送标头可能会产生深远的后果。以下是我目前碰巧想到的几个:

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

  2. 您可能会因莫名其妙的功能丢失而头疼。假设您正在实施某种支付网关,并在支付处理器成功确认后将用户重定向到特定 URL。如果发生某种 PHP 错误,甚至警告或多行结尾,付款可能仍未处理,用户可能仍未计费。这也是为什么不必要的重定向是邪恶的原因之一,如果要使用重定向,必须谨慎使用。

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

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

  5. 最后,许多 PHP 框架,包括 SymfonyZend 和 Laravel(在编码指南中没有提到这一点,但它遵循了相应内容)和 PSR-2 标准(第 2.2 项)都要求省略结束标记。PHP手册本身(1,2),Wordpress,Drupal和许多其他PHP软件,我猜,建议这样做。如果您只是养成遵循标准的习惯(并为您的代码设置 PHP-CS-Fixer),您可以忘记这个问题。否则,您将始终需要牢记这个问题。

奖励:与这 2 个角色相关的一些陷阱(实际上是目前一个):

  1. 甚至一些知名的库也可能包含过多的行尾。一个例子是 Smarty,即使是最新版本的 2.* 和 3.* 分支也有这个。因此,一如既往,请注意第三方代码。奖励中的奖励:用于删除不必要的PHP结尾的正则表达式:将包含PHP代码的所有文件中的空文本替换。?>(\s*\?>\s*)$

评论

0赞 frnhr 1/21/2013
我用来用Netbeans IDE查找标签的正则表达式略有不同,用于“查找和替换”对话框: 简短说明:changeset.hr/blog/miscellaneous/catch-near-eof-with-regex\?>(?s:.){0,10}\Z
0赞 Halil Özgür 1/21/2013
@Cek,它会捕获任何 10 个字符或以下的文本(包括代码):例如,它与 - 并且会删除 - 在 中匹配 - 并将删除 。我们只想清除关闭标记。?>?> Hello<?php echo "test"; ?> Hello
7赞 Artem Russakovskii 6/9/2014
更糟糕的是,带有 PHP 5.4 的 apache 2.4.6 实际上会在我们的生产机器上出现错误,当结束标签后面有空位时。我只是浪费了几个小时,直到我最终用 strace 缩小了错误范围。这是 apache 抛出的错误: .[core:notice] [pid 7842] AH00052: child pid 10218 exit signal Segmentation fault (11)
3赞 Halil Özgür 2/15/2015
@INTPnerd 哦,这个问题和大多数答案都与标题有关,所以我认为任何阅读此线程的人都会对此有所了解。这里许多答案中的潜在问题和问题的实际原因是后面不需要的空格,这(就像任何输出一样)导致标头在输出后立即发送。没有“HTML 标头”(不相关的 HTML5 标记除外)。?><header>
2赞 Erutan409 7/31/2015
无论全局修饰符如何,这都应该有效: \s*\?>\s*\Z 注意末尾的“\Z”。它确保您捕获 php 结束标记,当且仅当它是文件末尾的最后一个非空格时。
5赞 Maxime Pacary 2/27/2012 #9

优点

缺点

结论

我想说的是,支持省略标签的论点看起来更强大(有助于避免 header() + 它是 PHP/Zend“推荐”的大麻烦)。我承认,就语法一致性而言,这不是我见过的最“漂亮”的解决方案,但还有什么比这更好的呢?

6赞 user1238364 2/29/2012 #10

“除了标头问题之外,还有其他很好的理由跳过结束的php标签吗?”

您不希望在生成二进制输出、CSV 数据或其他非 HTML 输出时无意中输出无关的 whitepace 字符。

评论

1赞 eswald 7/4/2012
我有一个客户抱怨,因为他们的 XML 解析器在开头有一个额外的空行时拒绝了我们的输出。更糟糕的是,它只发生在七台服务器中的一台服务器上,在未修订的配置文件中的结束标记后多了一行。
7赞 Artem Russakovskii 6/9/2014 #11

除了已经说过的所有内容之外,我还将抛出另一个原因,这对我们来说是一个巨大的痛苦。

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

这是Apache抛出的错误:

[core:notice] [pid 7842] AH00052: child pid 10218 exit signal Segmentation fault (11)
2赞 mip 7/9/2014 #12

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

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

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

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

当然,PHP语法不是严格的SGML/XML/HTML,你创建一个文档,它不是SGML/XML/HTML,就像你可以把HTML变成XHTML是否符合XML一样。

  • 在某些时候,您可能希望连接源。如果您通过省略结束标记引入不一致,这将不像简单地这样做那么容易。cat source1.php source2.php?>

  • 如果没有,就很难判断文档是处于PHP转义模式还是PHP忽略模式(PI标签可能已打开)。如果您始终将文档保持在 PHP 忽略模式,生活会更轻松。这就像使用格式良好的 HTML 文档与具有未关闭、嵌套不良的标签等的文档相比。?><?php

  • 似乎像 Dreamweaver 这样的一些编辑器可能存在 PI 未打开的问题 [1]。

0赞 Daniele Cruciani 12/31/2015 #13

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

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

在案例 1.结束标签是完全没有用的,在这种情况下,我也希望看到只有 1(一)个 php 打开标签和 NO(零)结束标签。这是一个很好的做法,因为它使代码干净并将逻辑与表示分开。 对于表示案例(2.),一些人发现关闭所有标签(甚至是PHP处理的标签)是很自然的,这导致了混淆,因为PHP实际上有2个单独的用例,不应该混淆:逻辑/微积分和表示

18赞 Asaph 8/23/2016 #14

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

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

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