Закрывающий тег 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
Наконец, есть два способа сделать это правильно.
Добавление линии разрыва вручную:
nav ul id: "test" li @<?= $Var . "\n"; ?> li @About li @Contact
Запись пробела после закрывающего тега PHP (??).
Почему первый случай, <?= $Var; ?>
, игнорируя перевод строки после закрывающего тега PHP? Я не смог ничего найти, так как Google принес слишком много результатов о том, почему вы должны игнорировать закрывающий тег для каждого поиска, а не то, что я хотел найти.
1 ответ
Обновить:
Глядя на сканер Zend Language 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, где есть переводы строки, для всех намерений и целей, представленных \n
escape-последовательность, добавив, что char вручную может не дать желаемого результата, скажем, в системе Windows (которая использует \r\n
), Системы Apple используют \r
...
В PHP есть константа, обеспечивающая правильную подачу строк в зависимости от платформы, на которой работает ваш код: PHP_EOL
, Почему бы не использовать это:
<?= $bar, PHP_EOL; ?>
Если вам интересно: да, это $bar
запятая PHP_EOL
ты видишь там. Зачем? Думать о echo
или же <?=
как С ++ COUT
Это конструкция, которая просто выталкивает все, что вы добавляете, в выходной поток, является ли она конкатенационной строкой или просто списком переменных, разделенных запятыми: это не волнует.
Теперь следующий раздел моего ответа немного не по теме, но это просто что-то настолько простое и самоочевидное, и все же многие люди настолько не осознают этого, что я не могу удержаться от соблазна объяснить вещь или два о конкатенации строк.
PHP, как и большинство других известных мне языков, не заботится о том, сколько vars/vals нужно выдвинуть в поток вывода. Это то, для чего это. PHP и опять же: большинство языков заботятся о конкатенации строк: строка является своего рода постоянным значением. Вы не можете просто сделать строку длиннее, когда настроение вас захватывает. Серия символов должна храниться в памяти, памяти, которая должна быть выделена для размещения более длинной строки. Что эффективно делает конкатенация (в лучшем случае), так это:
- вычислить длину строки1 и строки2
- выделить дополнительную память, необходимую для объединения строки 2 в строку 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';
, Посмотрите на это, там есть переменные, которые могут быть чем угодно (массивы, объекты, строки huuuge..., там тоже есть целое число... замените точки запятыми и вставьте их в echo
Конструировать просто намного проще, чем даже начать думать о написании кода, необходимого для правильной конкатенации всех этих значений вместе...
Извините, что немного отошел, но, учитывая, что это так, ИМО, так просто, я чувствую, что все должны знать об этом...