PHP结束标记删除换行符

时间:2013-12-15 15:21:46

标签: php html preprocessor line-breaks

我正在做experiment, an html preprocessor像SLIM或Jade。

这是正确的 PHP 代码:

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

这是预期的预处理html (是的,$ Var ==“测试”):

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

但是,在浏览器中,我将此错误的文字作为预处理器html

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

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

  1. 手动添加分隔线:

    nav
      ul id: "test"
        li
          @<?= $Var . "\n"; ?>
      li
        @About
      li
        @Contact
    
  2. 在PHP结束标记之后写一个空格(??)。

  3. 为什么第一个案例<?= $Var; ?>忽略了关闭PHP代码后的换行符?我真的找不到任何东西,因为谷歌带来了太多关于你为什么要忽略的结果每次搜索的结束标记,而不是我想要找到的。

1 个答案:

答案 0 :(得分:10)

更新
看一下zend语言扫描程序src,看起来我的“hunch”是正确的: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 */
}

只需在the zend_language_scanner.c and zend_language_scanner.l files here

中查找T_CLOSE_TAG即可

我目前正在扫描Zend引擎的源代码,但是我想是的,因为你发布的代码的最后一个字符就是结束标记({{1} }),它是生成输出的PHP。看到你没有告诉PHP输出换行符,理所当然地说PHP不会在你回响的任何内容中添加新行。
当然,PHP会忽略关闭标记后面的换行符,但由于某种原因,PHP确实似乎消耗了该换行符。我正在查看解析PHP脚本的C代码,但我认为它可能使用换行符,空格,逗号的分号以及所有这些作为标记来将输入组合成节点。
看作结束标记?>是一个真正的标记,也是PHP语法的一部分,很可能这就是引擎有效消耗换行的原因,以及为什么它不属于输出

通过在结束标记之后添加空格字符,可能会消耗空间,但新行不会消耗,因此这可能是您仍然看到换行显示的原因。 我也尝试在一些测试代码中添加两个换行符,的确如下:输出只显示了一个新行:

?>

输出:

foo:
    <?= $bar; ?>

    foobar

所以看来我的怀疑可能会持水。

然而,考虑到所有事情,以免你想要在Zend引擎源上进行攻击,手动添加换行并不是一个很好的任务。实际上,这是确保生成正确换行符的好方法:
假设您在一个健康的* NIX系统上编写了一些代码,其中换行符是foo: bar foobar 转义序列所代表的所有意图和目的,手动添加该字符可能不会产生所需的输出,例如, Windows系统(使用\n),Apple系统使用\r\n ...
PHP有一个常量,可以确保您生成正确的换行符,具体取决于运行代码的平台:\r。为什么不使用它:

PHP_EOL

如果您想知道:是的,那就是<?= $bar, PHP_EOL; ?> 逗号 $bar您正在那里看到。为什么?将PHP_EOLecho视为C ++的<?=,它是一个构造,只是将你投掷的任何内容推送到输出流,将其作为连接字符串,或者只是逗号分开的变量列表:它不关心

现在,我的回答的下一部分略微偏离主题,但它只是所以基本的,不言自明的,但很多人都不太清楚它,我无法抗拒解释关于字符串连接的一两件事的诱惑 PHP,以及我所知道的大多数语言,并不关心它有多少vars / val来推送到输出流。这就是它的用途。 PHP,以及:大多数语言, 关心字符串的连接:字符串是一种常量值。当心情带你时,你不能只让字符串更长。一系列字符必须存储在内存中,内存必须分配以容纳更长的字符串。有效的连接(最佳情况场景)是:

  • 计算string1和string2的长度
  • 分配将string2连接到字符串1所需的额外内存
  • 将字符串2复制到新(额外)分配的内存

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

  • 计算两个字符串的长度
  • 分配内存,连接两个字符串所需
  • 将两个字符串复制到新分配的内存块
  • 将新指针分配给需要分配的任何变量
  • 释放任何未被引用的内存

第一种情况的一个例子:

COUT

可以翻译成以下C代码:

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

然而,只需这样做:

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 这样的东西。看看它,那里有变量,可能是任何东西(数组,对象,huuuge字符串......,那里也有一个整数......用逗号替换点并将其推送到$foo = 'I ' . ' am '. 'The'. ' ' .$result.' of some'.1.' with a dot'.' fetish';构造只是比开始考虑编写正确连接所有这些值所需的代码一样容易得多...
对不起,稍微离开这里,但看到这是,IMO,这么基本,我觉得好像每个人都应该意识到这一点......