Закрывающий тэг PHP удаляет фид строки

Я делаю эксперимент, препроцессор html, такой как SLIM или Jade.

Это код PHP, который кажется правильным:

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

Это ожидаемый предварительно обработанный html (да, $ Var == "Test"):

 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 (??).

Почему первый случай, <?= $Var; ?> <?= $Var; ?> , игнорируя фид строки после закрытия PHP-тега? Я не мог ничего найти, так как Google принес слишком много результатов о том, почему вы должны игнорировать закрывающий тег для каждого поиска, который я сделал, а не того, что я хотел найти.

Обновить:
Глядя на сканер 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 в файлах zend_language_scanner.c и zend_language_scanner.l здесь


В настоящее время я просматриваю исходный код движка Zend, но я бы предположил, что, поскольку последний символ кода, который вы опубликовали, просто закрывающий тег ( ?> ), Это PHP, который генерирует выход. Увидев, что вы не говорите PHP, чтобы выводить фид-канал, вполне понятно, что PHP не добавит новую строку к тому, что вы эхом.
Символ строки, который следует за закрывающим тегом, конечно, игнорируется PHP, но по какой-то причине PHP действительно потребляет этот фид строки. Я смотрю на код C, который анализирует ваш PHP-скрипт, но я думаю, что он может использовать новые строки, пробелы, полуколоны запятой и все это, как токены, чтобы блокировать ввод в узлы.
Видя как закрывающий тег ?> – это бинарный токен и часть грамматики PHP. Возможно, именно так, что линия-канал эффективно потребляется движком, и почему он не является частью вывода.

Добавив пробел после закрывающего тега, пространство может быть использовано, но в новой строке нет, поэтому возможно, что вы все еще видите отображение строки.
Я также попытался добавить 2 строковых канала к некоторому тестовому коду, и действительно: на выходе было показано только 1 новую строку:

 foo: <?= $bar; ?> foobar 

Вывод:

 foo: bar foobar 

Казалось бы, мои подозрения могут содержать воду.

Тем не менее, все рассмотренные вещи, чтобы вы не захотели сбежать от источника двигателя Zend, добавление линейного фида вручную не так уж и больно. Фактически, это хороший способ обеспечить правильные строки:
Предположим, вы написали какой-то код в искушенной системе * NIX, где строки-строки, во всех смыслах и целях, представляемые escape-последовательности \n , добавив, что char вручную может не дать нужный результат, скажем, системе Windows ( который использует \r\n ), системы Apple используют \r
PHP имеет константу, чтобы убедиться, что вы производите правильные строки, в зависимости от платформы, на которой работает ваш код: PHP_EOL . Почему бы не использовать это:

 <?= $bar, PHP_EOL; ?> 

В случае, если вам интересно: да, это $bar запятая PHP_EOL которую вы видите там. Зачем? Подумайте об echo или <?= Как C ++ COUT , это конструкция, которая просто толкает все, что вы бросаете на нее в выходной поток, погода это конкатенированная строка или просто список переменных, разделенных запятыми: это не волнует ,

Теперь следующий раздел моего ответа идет немного не по теме, но это просто что-то такое основное и самоочевидное, и все же многие люди так не знают об этом, что я не могу устоять перед соблазном объяснить вещь или две о конкатенации строк.
PHP, и большинство языков, о которых я знаю, не заботятся о том, сколько vars / vals ему нужно нажать на выходной поток. Это для чего. PHP и еще раз: большинство языков, не заботятся о конкатенации строк: строка – это своего рода постоянное значение. Вы не можете просто сделать строку дольше, когда настроение вас заберет. Ряд символов должен храниться в памяти, память должна быть выделена для размещения более длинной строки. Какая конкатенация эффективно (наилучший сценарий), такова:

  • вычислить длину строки1 и строки2
  • выделить дополнительную память, необходимую для выполнения строки string2 в строке 1
  • скопируйте строку 2 в эту новую (дополнительную) выделенную память

В то время как во многих случаях происходит то, что происходит на самом деле:

  • вычислять длины обеих строк
  • выделить память, необходимую для согласования обеих строк
  • скопируйте обе строки в только что выделенный блок памяти
  • назначить новый указатель на любую переменную, требующую назначения
  • освободить любую память, на которую больше не ссылаются

Пример первого случая:

 $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'; $foo = 'I ' . ' am '. 'The'. ' ' .$result.' of some'.1.' with a dot'.' fetish'; , Посмотрите на это, там есть переменные, это может быть что угодно (массивы, объекты, строки huuuge …, там тоже есть целое число), замените точки запятой и нажав ее на echo конструкцию, просто так много проще, чем даже начать созерцать запись кода, необходимого для правильной конкатенации всех этих значений вместе …
Извините за дрейф здесь немного, но, видя, что это так, ИМО, настолько базовый, мне кажется, что все должны знать об этом …