更新:
望着Zend的语言扫描仪SRC,它似乎是我的“预感”是正确的:在T_CLOSE_TAG
令牌似乎可能包含换行字符。更重要的是,它也希望似乎一个结束分号中包含关闭标签是可选的脚本的最后一条语句...
<ST_IN_SCRIPTING>("?>"|"</script"{WHITESPACE}*">"){NEWLINE}? {
ZVAL_STRINGL(zendlval, yytext, yyleng, 0); /* no copying - intentional */
BEGIN(INITIAL);
return T_CLOSE_TAG; /* implicit ';' at php-end tag */
}
只要看看T_CLOSE_TAG
在the zend_language_scanner.c and zend_language_scanner.l files here
我扫描当前Zend引擎的来源,可以肯定的,但我猜,因为你发布的代码的最后一个字符(或多个),简单地说,结束标记(?>
),这是该PHP正在生成输出。鉴于您不会告诉PHP输出换行符,这意味着PHP不会为您回应的任何内容添加新行。
后面的结束标记,当然,用PHP忽略,但由于某些原因,PHP确实似乎消耗该行料换行字符。我看它分析你的PHP脚本的C代码,但我想作为输入令牌,以块为节点可能会使用新行,空格,逗号分号和所有。
看到结束标记?>
是一个真实的标记,也是PHP语法的一部分,很可能这是引擎有效使用换行的原因,也是它为什么不是输出的一部分。
通过关闭标签后添加一个空格字符,空间可能会被消耗掉,但新线是没有,所以这可能是为什么你看到的仍然是换行显示。
我也尝试添加2个换行符一些测试代码,而事实上:输出显示,只有1个新行:
foo:
<?= $bar; ?>
foobar
输出:
foo:
bar
foobar
所以它似乎是我的怀疑可能会有水。
然而,考虑到所有的事情,为了避免你想要在Zend引擎源代码中进行攻击,手动添加换行符并不是什么大问题。实际上,确保正确的生成的换行符是一个好方法:
假设您在健康* NIX系统上编写了一些代码,其中换行符为\n
代表的所有意图和目的序列,手动添加字符可能不会产生所需的输出,例如,Windows系统(使用\r\n
),Apple系统使用\r
...
PHP有一个常量,以确保您生成正确的换行符,具体取决于代码运行的平台:PHP_EOL
。为什么不使用:
<?= $bar, PHP_EOL; ?>
如果你想知道:是的,这是$bar
逗号PHP_EOL
你看到那里。为什么?把echo
或<?=
想象成C++的COUT
,它是一个构造,它只是将你要抛出的东西推到输出流上,把它变成一个串联的字符串,或者只是一个用逗号分隔的变量列表:它并不关心 。
现在,我的回答下面的部分稍微会偏离主题,但它只是一些所以基本和不言自明的,但仍然有许多人是如此未意识到这一点,我不能抵制解释关于字符串连接的一两件事的诱惑。
PHP和我知道的大多数语言都不关心它必须推送到输出流有多少个变量/ val。这是它的目的。 PHP,并再次:大多数语言,确实关心字符串串联:字符串是一种常数值。心情带给你的时候,你不能再长一段。一系列字符必须存储在内存中,必须分配内存以容纳更长的字符串。什么级联有效呢(最好的情况下),是这样的:字符串1和字符串的
- 计算长度
- 分配给Concat的字符串2到字符串需要额外的内存1
- 复制串2到新(额外)分配的内存
然而,在很多情况下,实际发生的事情是:
- 补偿两个字符串
- 分配内存,以Concat的两个字符串
- 副本所需的UTE长度两个字符串到新分配的内存块
- 分配新指针的变数,需要分配
- 释放所有内存ISN”吨引用了
第一种情况的一个例子:
$str1 = 'I am string constant 1';
$str2 = ' And I\'ll be concatenated';
$str1 .= $str2;
能翻译下面的C代码:
char *str1, *str2;
//allocate mem for both strings, assign them their vals
str1 = realloc(str1,(strlen(str1) + strlen(str2)+1));//re-allocate mem for str1
strncat(str1, str2, strlen(str2);//concatenate str2 onto str1
然而,通过简单地这样做:
$str3 = $str1 . $str2;
你实际上做的是:
char *str3 = malloc((strlen(str1) + strlen(str2) + 1)*sizeof(char));
strcpy(str3, str1);//copy first string to newly allocated memory
strcat(str3, str2);//concatenate second string...
而且好像是间没有'够了,只要想一下这个代码暗示:
$str1 = $str2 . $str1;
没错,果然:
char *str3 = malloc((strlen(str1) + strlen(str2) + 1)*sizeof(char));
strcpy(str3, str2);//copy seconds string to start of new string
strcat(str3, str1);//add first string at the end
free(str1);//free memory associated with first string, because we're reassigning it
str1 = str3;//set str1 to point to the new block of memory
现在我还没有算到了真正的串联噩梦还没有(不用担心,我不会要么)。东西像$foo = 'I ' . ' am '. 'The'. ' ' .$result.' of some'.1.' with a dot'.' fetish';
。看看它,里面有变量,可能是任何东西(数组,对象,huuuge字符串......,里面还有一个整数......用逗号代替点,并将它推到echo
构造就是这么多比甚至开始考虑编写将所有这些值正确拼接在一起所需的代码更容易...
对不起,稍微偏离这里,但看到这样,IMO,如此基本,我感觉好像每个人都应该知道这一点...
我刚刚在使用'= $var ?>''在HTML'
'标签内的多行结尾处输出变量时,我注意到了这个问题。我需要在每一行之后添加一个额外的换行符以保留文本输出格式正确,但我真的不喜欢这种行为,尽管我能理解为什么当文件以'?>'结尾时(可能是一个不包含任何内容的包含文件),可能会添加这个文件以防止在文件末尾出现多余的换行符输出。 – Haprog