为什么会忽略closures标签?

我一直在阅读,在文件的末尾使用PHPclosures标签很不好。 标题问题似乎在以下的背景下是不相关的(迄今为止这是唯一的一个很好的论点):

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

每本优秀的练习本和wiki都以这个“规则”开始,但没有人提供很好的理由。 是否有另一个很好的理由跳过结尾的PHP标签?

虽然我不记得任何其他原因,但比正常情况下发送标题可能会产生深远的影响。 以下是刚才我想到的其中几个:

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

  2. 您可能会因无法解决的function丧失而感到头疼。 假设您正在实施某种付款网关,并在付款处理器成功确认后将用户redirect到特定的url。 如果出现某种PHP错误,甚至是警告,或者发生了额外的行结束,那么付款可能仍然是未处理的,并且用户可能看起来仍然没有收费。 这也是不必要的redirect是邪恶的原因之一,如果要使用redirect,必须谨慎使用。

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

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

  5. 最后,包括Symfony , Zend和Laravel在内的许多PHP框架(在编码指南中没有提及这一点,但是它遵循了这个规定 ), PSR-2标准 (第2.2条)要求省略结束标签。 PHP手册本身( 1,2 ), WordPress , Drupal和许多其他PHP软件,我猜,build议这样做。 如果你只是习惯遵循这个标准(并且为你的代码设置PHP-CS-Fixer ),你可以忘记这个问题。 否则,你将永远需要在脑海中保持这个问题。

奖金:与这两个字符有关的几个陷阱(实际上是一个):

  1. 甚至一些着名的图书馆可能会在?>之后包含多余的行结尾。 一个例子是Smarty,即使是最新版本的2. *和3. *分支都有这个。 所以,一如既往, 注意第三方代码 。 奖金奖金:删除不必要的PHP结尾的正则expression式:在包含PHP代码的所有文件中用空文本replace(\s*\?>\s*)$

你应该离开PHP结束标记( ?> )的原因是程序员不会无意中发送额外的换行符。

你不应该离开PHP结束标签的原因是因为它导致了PHP标签的不平衡,任何半心的程序员都可以记住不添加额外的空白。

所以对于你的问题:

是否有另一个很好的理由跳过结尾的PHP标签?

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

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

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

  2. PHP不是XML。 PHP不需要严格遵守XML的严格标准,写得很好,而且function齐全。 如果一个缺失的结束标记使你恼火,你可以使用一个结束标记,这不是一种规则。

这是一个新手编码风格的build议 ,善意的, 手册build议。

  • 但是只能解决已经发送的常见头文件 (原始输出, BOM ,通知等)以及后续问题。

  • PHP实际上包含了一些神奇的东西,可以在?>闭包令牌之后吃掉单行换行。 尽pipe存在着历史性的问题 ,并且让新来者仍然容易受到片状编辑的影响,并且在之后的其他空白中不知不觉地洗牌。

  • 在风格上,一些开发人员更喜欢将<?php?>视为SGML标签/ XML处理指令,意味着尾随的近似标记的平衡一致性。 (其中,顺便说一句,对于依赖关联类是有用的 ,包括取代低效的逐个文件自动加载。

  • 开头的<?php有一些不常见的特点,就是PHPs shebang (每个binfmt_misc完全可行),从而validation了相应的closures标签的冗余性。

  • 经典的PHP语法指南要求?>\n与最近的(PSR-2)同意忽略之间有明显的build议差异。
    (为了logging:Zend框架假设一个在另一个并不意味着其固有的优势。这是一个错误的观念,专家被吸引到/笨重的API的目标受众)。

  • 供应链pipe理和现代集成开发环境提供内置的解决scheme,大多减轻密切的标签pipe理工作。

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

closures标签变化

  • 经常 >closures标记也被称为T_CLOSE_TAG ,或因此“closures标记”。

  • 它包含了一些更多的化身,因为PHP的魔法换行饮食

    > \ n (Unix换行符)

    > \ r (回车,经典MAC)

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

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

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

  • 经常被忽略,但是在PHP7删除它们之前 ,常规的<?php开放标记可以与罕用的</script> 有效地配对为奇数闭包标记

  • 硬closures标签 ”甚至不是一个 – 只是把这个词作为比喻。 概念和明智的__halt_compiler应该被认为是密切的标记。

     __HALT_COMPILER(); ?> 

    基本上,这个标记器之后放弃了任何代码或纯HTML部分。 特别是PHAR桩可以利用它,或者如图所示的冗余组合。

  • 同样,也是无效的return; 在包含脚本中很less替代,渲染任何?>后面的空白无效。

  • 然后有各种软/人造密切的标签变化; 鲜为人知并且很less使用,但通常是每个注释掉的令牌:

    • 简单的间距// ? > // ? >来逃避PHPs tokenizer的检测。

    • 或者是一个正则expression式可以理解的代码// ﹖﹥ (U + FE56小问号,U + FE65小angular度支架)。

    对PHP没有任何意义 ,但对于PHP不知道或半知晓的外部工具包可以有实际的用途。 再一次cat合脚本的想法,结果// ? > <?php // ? > <?php连接,内联保留以前的文件切片。

所以有一个紧急标签遗漏的紧急情况,但实际的替代scheme。

手动保姆?>closures标签是不是很现代的任何方式。 总是有自动化工具(即使只是sed / awk或正则expression式)。 尤其是:

phptags标签整理

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

这通常可以用来 – 为第三方代码--unclose php标签,或者只是修复任何(和所有)实际的空白/ BOM问题:

  • phptags --warn --whitespace *.php

它还处理 – --long标签转换等运行时/configuration兼容性。

这不是一个标签…

但是,如果你有它,你可能会在后面有空白的风险。

如果你使用它作为一个文档的顶部包括,你可能会最终插入空白(即内容),然后再尝试发送HTTP标头…这是不允许的。

这不是让closures?>在。

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

将。

有一次,你一定是懒得保安

那么,有两种方法来看待它。

  1. PHP代码只不过是一组XML处理指令 ,因此任何扩展名为.php都不过是一个XML文件,而这些文件恰恰是为了parsingPHP代码而发生的。
  2. PHP恰好为其打开和closures标签共享XML处理指令格式。 基于此,具有.php扩展名的文件可以是有效的XML文件,但不需要。

如果你相信第一条路线,那么所有的PHP文件都需要closures结束标记。 省略它们将会创build一个无效的XML文件。 然后,没有打开<?xml version="1.0" charset="latin-1" ?>声明,您将不会有一个有效的XML文件…所以这不是一个主要问题…

如果你相信第二条路线,这为两种types的.php文件打开了大门:

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

基于此,只有代码的文件才能结束,而没有结束?>标记。 但是XML代码文件不能结束而不能结束?>因为它会使XML无效。

但是我知道你在想什么 你在想什么是重要的,你永远不会直接渲染一个PHP文件,所以谁在乎它是否是有效的XML。 那么,如果你正在devise一个模板,这一点很重要。 如果它是有效的XML / HTML,一个普通的浏览器将不会显示PHP代码(它被视为一个注释)。 所以你可以模拟出模板,而不需要在内部运行PHP代码。

我并不是说这很重要。 这只是我看不到太多expression的观点,所以有什么更好的地方来分享它…

就个人而言,我不closures库文件中的标签,但在模板文件中做…我认为这是一个个人的偏好(和编码指南),比什么都难

根据文档 ,如果出现以下原因,最好省略结束标记:

如果文件是纯PHP代码,则最好在文件末尾省略PHP结束标记。 这样可以防止在PHP结束标记之后添加意外的空白或新行,这可能会导致不必要的效果,因为当程序员无意在脚本中的任何位置发送输出时,PHP将开始输出缓冲。

http://php.net/manual/en/language.basic-syntax.phptags.php

那么,我知道原因,但我不能表明:

对于只包含PHP代码的文件,结束标记( ?> )从不允许。 这不是PHP所要求的,省略了它可以防止意外的后续空白注入响应。

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

除了已经说过的一切之外,我还要抛出另一个让我们debugging的巨大痛苦的原因。

PHP 5.4的Apache 2.4.6实际上在我们的生产机器上分割错误时,在closuresphp标签后面有空的空间。 我只是浪费了几个小时,直到我终于用strace缩小了这个bug。

这是Apache抛出的错误:

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

优点

  • closures任何打开的标签是合乎逻辑的,就像其他语言一样。 不仅X(HT)ML标签,而且大括号,括号…
  • 对于初学者来说,不那么困惑 。

缺点

  • 避免在结束标记之后无意中添加空格造成的头痛,因为它会中断header()函数的行为…一些编辑器或FTP客户端/服务器也被称为自动更改文件的结尾(至less,这是它们的默认configuration)
  • PHP手册说closures标签是可选的 , Zend甚至禁止它 。

结论

我想说的赞成省略标签的观点看起来更强大(有助于避免头痛 +)这是PHP / Zend“推荐”)的大头痛。 我承认这不是我在语法一致性方面所见过的最“美丽”的解决scheme,但还有什么更好的?

“除了标题问题之外,还有另一个好的理由来跳过结尾的php标签吗?”

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

由于我的问题被标记为这个重复,我认为可以发布为什么省略结束标记?>可以出于一些理想的原因。

  • 通过完整的处理指令语法( <?php ... ?> ),PHP源代码是有效的SGML文档,SGML文档可以被parsing和处理,而SGML分析器没有问题。 有了额外的限制,它也可以是有效的XML / XHTML。

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

注意:另外请注意,如果您将PHPembedded到XML或XHTML中,您将需要使用<?php?>标记以保持与标准兼容。

当然,PHP语法并不是严格的SGML / XML / HTML,您可以创build一个不是SGML / XML / HTML的文档,就像您可以将HTML转换为符合XML的XHTML一样。

  • 在某些时候,您可能想要连接源代码。 如果通过忽略closures?>标记引入不一致,那么这将不如简单地执行cat source1.php source2.php那么简单。

  • 如果没有?>很难判断文档是否处于PHP转义模式或PHP忽略模式(PI标记<?php可能已被打开或没有被打开)。 如果您始终将您的文档保留为PHP忽略模式,生活会更轻松。 就像使用格式良好的HTML文档的工作相比,文档没有封闭,嵌套不好的标签等。

  • 看起来像Dreamweaver这样的编辑可能会遇到PI左开的问题[1] 。

如果我正确地理解了这个问题,那么它必须处理输出缓冲以及这可能对closures/结束标记的影响。 我不确定这是一个完全正确的问题。 问题是,输出缓冲区并不意味着所有的内容在发送到客户端之前都保存在内存中。 这意味着一些内容是。

程序员可以故意刷新缓冲区或输出缓冲区,PHP中的输出缓冲区选项是否真的会改变结束标记如何影响编码? 我会认为这不是。

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

有2个可能的使用PHP代码:

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

在情况下1.结束标签是完全unusefull,我也想看到只有1(一)PHP开放标签和NO(零)结束标签在这种情况下。 这是一个很好的做法,因为它可以使代码变得清晰,并将逻辑与演示分开 对于呈现案例(2.),一些人发现closures所有标记(甚至PHP处理的标记)是自然的,这导致了混乱,因为PHP实际上有两个独立的用例,不应混用:logic / calculus和演示文稿