PHP结束标记删除换行符 [英] PHP closing tag deletes the line feed

查看:81
本文介绍了PHP结束标记删除换行符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个实验,一个html预处理器,如SLIM或Jade。



这是 PHP 代码,看起来不错:

  nav 
ul id:test
li
@<?= $ Var; ?>
li
@关于
li
@Contact

这是预期的预处理html (是,$ Var ==Test):

  nav 
ul id:test
li
@Test
li
@关于
li
@Contact

但是,在浏览器中,我将错误 预处理器HTML

  nav 
ul id:test
li
@Test li
@About
li
@Contact

最后,有两种方法可以使其正确。


  1. 手动添加断线:

    p>

      nav 
    ul id:test
    li
    @<?= $ Var。 \\\
    ; ?>
    li
    @关于
    li
    @Contact



为什么在PHP结尾标记(??)后写一个空格第一种情况,<?= $ Var; ?>> ,在关闭PHP标记后忽略换行符我找不到任何内容,因为Google带来了太多关于为什么应忽略每次搜索的结束标记的结果不是我想要找到的。

解决方案

b看着zend语言扫描程序src,我的hunch看起来是正确的: T_CLOSE_TAG 标记似乎可能包含换行符焦炭。更重要的是,对于包含结束标签的脚本中的最后一条语句,结尾分号似乎是可选的...

 < ST_IN_SCRIPTING>(; | < /脚本 >?{WHITESPACE} * > 中){NEWLINE}? {
ZVAL_STRINGL(zendlval,yytext,yyleng,0); / *没有复制 - 故意* /
BEGIN(INITIAL);
返回T_CLOSE_TAG; / *隐式';'在php-end标签* /
}

zend_language_scanner.c和zend_language_scanner中的 T_CLOSE_TAG 。 l文件






目前我正在扫描Zend引擎的来源,但是,我想这是因为你发布的代码的最后一个字符就是结束标记(?> ),它是生成输出。由于您并未告诉PHP输出换行符,因此PHP不会在您回应的内容中添加新行。
<
>换行字符当然,结束标记被PHP忽略,但由于某种原因,PHP似乎确实占用了该换行符。我正在研究解析PHP脚本的C代码,但我认为它可能会使用新行,空格,逗号的分号和所有作为标记的输入到节点中。

视为结束标记?> 是一个真正的标记,也是PHP语法的一部分,很可能这就是换行的地方有效地被引擎消费,为什么它不是输出的一部分。



通过在结束标签后面添加一个空格字符,该空间可能会被消耗,行不是,所以这可能就是为什么你仍然看到换行显示。

我也尝试在一些测试代码中添加2行换行,事实上:输出显示只有1个新行:

  foo:
<?= $ bar; ?>

foobar

输出:

  foo:
bar
foobar


$ b因此,看起来我的猜测可能会持续。

然而,考虑到所有的事情,为了避免你想侵入Zend引擎来源,手动添加换行并不是什么大事。实际上,确保生成正确的 换行符是一种好方法:

假设你在一个健康的* NIX系统上编写了一些代码,其中换行是,对于由 \ n 转义序列表示的所有意图和目的,手动添加该char可能不会在例如windows系统(使用 \r\\\
),Apple系统使用 \r ... ...
PHP有一个常数,以确保您生成正确的换行符,具体取决于代码运行的平台: PHP_EOL 。为什么不使用它:

 <?= $ bar,PHP_EOL; ?> 

如果您想知道:是的,那是 $ bar 逗号 PHP_EOL 你在那里看到。为什么?可以把 echo 或<?= 看作C ++的 COUT ,它是一种构造,只要将所有抛出的内容推送到输出流,将其视为串联的字符串,或者只是逗号分隔的变量列表:不关心。 p>

现在,我的答案的以下部分略微偏离主题,但它只是 so 基本的和不言而喻的,然而许多人们对此没有意识到,我无法抗拒解释关于字符串连接的一两件事的诱惑。

PHP和我所知道的大多数任何语言都不关心有多少变量/ vals必须推送到输出流。这是它的目的。 PHP,以及大多数语言,确实关心字符串的连接:字符串是一种常数值。心情带给你的时候,你不能再长一段。一系列字符必须存储在内存中,必须分配内存以容纳更长的字符串。什么级联有效地做(最好的情况下),是这样的:


  • 计算字符串1和字符串2的长度
  • 分配需要的额外内存以将string2连接到字符串1上

  • 将字符串2复制到新(额外)分配的内存中


在很多情况下,实际发生的是:


  • 计算两个字符串的长度
  • >
  • 分配内存,将所有字符串连接到一起

  • 将两个字符串复制到新分配的内存块中
  • 指向任何变量需要分配的指针

  • 释放所有未被引用的内存



第一种情况的示例:

  $ str1 ='我是字符串常量1'; 
$ str2 ='我将被连接';
$ str1。= $ str2;

可以转换为以下C代码:

  char * str1,* str2; 
//为这两个字符串分配mem,为它们分配vals
str1 = realloc(str1,(strlen(str1)+ strlen(str2)+1)); //为str1重新分配mem
strncat(str1,str2,strlen(str2); //将str2连接到str1

然而, ,只需做到这一点:

  $ str3 = $ str1。$ str2; 



您实际做的是:

  char * str3 = malloc(strlen(str1)+ strlen(str2)+ 1)* sizeof(char)); 
strcpy(str3,str1); //将第一个字符串复制到新分配的内存
strcat(str3,str2); //连接第二个字符串...

是不够的,只要想一想这个代码的含义即可:

  $ str1 = $ str2。$ str1; 

是的,果然:

  char * str3 = malloc(strlen(str1)+ strlen(str2)+ 1)* sizeof(char)); 
strcpy(str3,str2 ); //将秒字符串复制到新stri的开头ng
strcat(str3,str1); //在结尾添加第一个字符串
free(str1); //释放与第一个字符串相关的内存,因为我们正在重新分配
str1 = str3; //设置str1指向新的内存块

现在我还没有得到到真正的串联噩梦呢(不要担心,我也不会去)。东西像 $ foo ='我'。 'am'。 的。 ''。$ result。'of some'.1。'with a dot'。'fetish'; 。看看它,里面有变量,可能是任何东西(数组,对象,huuuge字符串......,里面还有一个整数......用逗号代替点并将它推到 echo 构造只是比开始考虑编写将所有这些值正确连接在一起所需的代码容易得多...

对不起,稍微偏离这里,但看到因为这是国际海事组织,所以很基本,我觉得每个人都应该知道这一点......

I'm doing an experiment, an html preprocessor like SLIM or Jade.

This is the PHP code that seems right:

nav
  ul id: "test"
    li
      @<?= $Var; ?>
    li
      @About
    li
      @Contact

This is the expected pre-processed html (yes, $Var == "Test"):

nav
  ul id: "test"
    li
      @Test
    li
      @About
    li
      @Contact

However, in the browser I get this wrong text as the pre-processor html:

nav
  ul id: "test"
    li
      @Test    li
      @About
    li
      @Contact

Lastly, there are two ways to make it correct.

  1. Adding the break line manually:

    nav
      ul id: "test"
        li
          @<?= $Var . "\n"; ?>
      li
        @About
      li
        @Contact
    

  2. Writing a space after the PHP closing tag (??).

Why is the first case, <?= $Var; ?>, ignoring the line feed after the closing PHP tag? I couldn't really find anything since google brought too many results about why you should ignore the closing tag for every search I did and not what I wanted to find.

解决方案

Update:
Looking at the zend language scanner src, it would seem that my "hunch" was correct: the T_CLOSE_TAG token would appear to possibly contain a newline char. What's more, It'd also seem that a closing semi-colon for the last statement in a script that contains a closing tag is optional...

<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 */
}

Just look for T_CLOSE_TAG in the zend_language_scanner.c and zend_language_scanner.l files here


I'm currently scanning the source of the Zend engine, to be sure, but I'd guess that, since the last char(s) of the code you posted are, simply, the closing tag (?>), it's PHP that is generating the output. Seeing as you're not telling PHP to output a line-feed, it stands to reason that PHP won't add a new line to whatever you're echoing.
The line-feed char that follows the closing tag is, of course, ignored by PHP, but for some reason, PHP does indeed seem to consume that line feed. I'm looking at the C code that parses your PHP script, but I'm thinking it might use new-lines, whitespace, comma's semi-colons and all that as tokens to chunk the input into nodes.
Seeing as the closing tag ?> is a bona-fide token, and part of the PHP grammar, It could well be that this is where the line-feed is effectively consumed by the engine, and why it's not part of the output.

By adding a space char after the closing tag, The space might be consumed, but the new-line isn't, so that might be why you're still seeing the line-feed show up.
I've also tried adding 2 line feeds to some test code, and indeed: the output showed only 1 new line:

foo:
    <?= $bar; ?>

    foobar

Output:

foo:
    bar
    foobar

So it would seem that my suspicions might hold water.

However, all things considered, lest you want to go hacking away at the Zend engine source, adding the line-feed manually isn't that much of a hasstle. In fact, it's a good way to ensure the correct line-feeds are generated:
Suppose you wrote some code, on a healty *NIX system, where line-feeds are, to all intents and purposes represented by the \n escape sequence, adding that char manually might not yield the desired output on, say, a windows system (which uses \r\n), Apple systems use \r...
PHP has a constant to ensure you're churning out the correct line-feeds, depending on the platform your code is running on: PHP_EOL. Why not use that:

<?= $bar, PHP_EOL; ?>

In case you're wondering: yes, that is $bar comma PHP_EOL you're seeing there. Why? Think of echo or <?= as C++'s COUT, it's a construct that just pushes whatever you're throwing at it to the output stream, weather it be a concatenated string, or just a comma separated list of variables: it doesn't care.

Now, the following section of my answer is going slightly off-topic, but it's just something so basic, and self-evident, and yet many people are so un-aware of it, that I can't resist the temptation of explaining a thing or two about string concatenation.
PHP, and most any language I know of, doesn't care about how many vars/vals it has to push to the output stream. It's what it's for. PHP, and again: most languages, does care about concatenation of strings: A string is sort of a constant value. You can't just make a string longer when the mood takes you. A series of chars have to be stored in memory, memory that has to be allocated to accommodate a longer string. What concatenation effectively does (best case scenario), is this:

  • compute length of string1 and string2
  • allocate additional memory required to concat string2 onto string 1
  • copy string 2 to that newly (extra) allocated memory

Whereas, in a lot of cases, what actually happens is:

  • compute lengths of both strings
  • allocate memory, required to concat both strings
  • copy both strings to that newly allocated memory block
  • assign the new pointer to whatever variable needs assigning
  • free up any memory that isn't referenced anymore

An example of the first case:

$str1 = 'I am string constant 1';
$str2 = ' And I\'ll be concatenated';
$str1 .= $str2;

Could translate to the following C code:

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

However, by simply doing this:

$str3 = $str1 . $str2;

What you're actually doing is:

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...

And as if that weren't enough, just think what this code implies:

$str1 = $str2 . $str1;

Yes, sure enough:

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

Now I haven't even gotten to the real concatenation nightmares yet (don't worry, I'm not going to either). Stuff like $foo = 'I ' . ' am '. 'The'. ' ' .$result.' of some'.1.' with a dot'.' fetish';. Look at it, there's variables in there, that might be anything (arrays, objects, huuuge strings..., there's an integer in there, too... replace the dots with comma's and pushing it to the echo construct just is so much easier than even begin contemplating writing the code required to correctly concatenate all of these values together...
Sorry for drifting off here slightly, but seeing as this is, IMO, so basic, I feel as though everyone should be aware of this...

这篇关于PHP结束标记删除换行符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆