Ссылка: Сравнение печати PHP и эха

182

В чем разница между PHP printи echo?

У переполнения стека много вопросов, касающихся PHP printи echoиспользования ключевых слов.

Цель этого поста - предоставить канонический справочный вопрос и ответ о PHP printи echoключевых словах, а также сравнить их различия и варианты использования.

user187291
источник
3
Я думаю, что здесь недостаточно о возвращаемом значении печати. Печать полезна для быстрого вывода отладочной информации или чего-то в этом роде: strpos ($ x, $ y)! == FALSE ИЛИ напечатать «что-то». Быстро печатать и хорошо читать. И «печать функции» было по какой-то причине неудобно читать (ваши аргументы кажутся ... странными и неочевидными) - это языковая конструкция, с ней гораздо хуже, что вы не можете сделать: переменные функции.
XzKto
1
Чтобы сохранить это открытым, необходимо сделать следующее: 1. разделить вопрос и ответ. 2. Ссылка / ссылка на существующий контент о предмете на Stack Overflow (вроде как здесь: stackoverflow.com/questions/3737139/… ), но в ответе. 3. Должен быть CW.
Кев
«Связанная колонка» - это хорошо, но она не очень сфокусирована. Чтобы повысить его ценность как канонического справочного вопроса и ответа, он также должен быть хорошо исследован, и ссылки на другие конкретные хорошие ответы могут повысить ценность.
Кев
На самом деле вопрос должен быть фактическим вопросом . Я могу добавить баннер для канонической части, как только вы закончите.
Тим Пост

Ответы:

185

Почему две конструкции?

Правда о печати и эхо заключается в том, что, хотя они представляются пользователям в виде двух отдельных конструкций, они действительно являются оттенками эха, если вы приступите к основам, т. Е. Посмотрите на внутренний исходный код. Этот исходный код включает в себя как синтаксический анализатор, так и обработчики кода операции. Рассмотрим простое действие, например отображение нуля. Используете ли вы echo или print, будет вызываться один и тот же обработчик "ZEND_ECHO_SPEC_CONST_HANDLER". Обработчик для печати делает одну вещь, прежде чем он вызывает обработчик для эха, он гарантирует, что возвращаемое значение для печати равно 1, следующим образом:

ZVAL_LONG(&EX_T(opline->result.var).tmp_var, 1);

(см. здесь для справки )

Возвращаемое значение - удобство, если вы хотите использовать print в условном выражении. Почему 1, а не 100? В PHP истинность 1 или 100 одинакова, то есть истинна, тогда как 0 в логическом контексте приравнивается к ложному значению. В PHP все ненулевые значения (положительные и отрицательные) являются истинными значениями, и это вытекает из наследства PHP в Perl.

Но, если это так, то можно задаться вопросом, почему echo принимает несколько аргументов, тогда как print может обрабатывать только один. Для этого ответа нам нужно обратиться к парсеру, а именно к файлу zend_language_parser.y . Вы заметите, что в echo встроена гибкость, позволяющая печатать одно или несколько выражений (см. Здесь ). в то время как печать ограничена печатью только одного выражения (см. там ).

Синтаксис

В языке программирования C и языках, на которые он влияет, таких как PHP, существует различие между утверждениями и выражениями. Синтаксически, echo expr, expr, ... exprявляется оператором, а print exprявляется выражением, поскольку оно оценивается как значение. Поэтому, как и другие утверждения, echo exprстоит сам по себе и не может быть включен в выражение:

5 + echo 6;   // syntax error

Напротив, print exprможет самостоятельно сформировать утверждение:

print 5; // valid

Или быть частью выражения:

   $x = (5 + print 5); // 5 
   var_dump( $x );     // 6 

Кто-то может подумать, printчто это унарный оператор, такой как !или, тем не ~менее, не оператор. Что !, ~ and printобъединяет то , что все они построены на PHP и каждый принимает только один аргумент. Вы можете использовать printдля создания следующего странного, но действительного кода:

    <?php 
    print print print print 7; // 7111

На первый взгляд результат может показаться странным, что последний оператор print сначала печатает свой операнд '7' . Но если вы копаете глубже и смотрите на действительные коды операций, это имеет смысл:

line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   3     0  >   PRINT                                            ~0      7
         1      PRINT                                            ~1      ~0
         2      PRINT                                            ~2      ~1
         3      PRINT                                            ~3      ~2
         4      FREE                                                     ~3
         5    > RETURN                                                   1

Самый первый код операции, который генерируется, соответствует «print 7». «~ 0» - это временная переменная, значение которой равно 1. Эта переменная становится операндом для следующего кода операции печати, который, в свою очередь, возвращает временную переменную, и процесс повторяется. Последняя временная переменная вообще не используется, поэтому она освобождается.

Почему printвозвращает значение, а echoнет?

Выражения оценивают до значений. Например, 2 + 3оценивает 5и abs(-10)оценивает 10. Поскольку print exprсамо по себе является выражением, то оно должно содержать значение, и оно имеет, непротиворечивое значение 1указывает на достоверный результат, и, возвращая ненулевое значение, выражение становится полезным для включения в другое выражение. Например, в этом фрагменте возвращаемое значение print полезно при определении последовательности функций:

<?php

function bar( $baz ) { 
   // other code   
}
function foo() {
  return print("In and out ...\n");
}

if ( foo() ) {

     bar();
}

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

<?php
$haystack = 'abcde';
$needle = 'f';
strpos($haystack,$needle) !== FALSE OR print "$needle not in $haystack"; 

// output: f not in abcde

Как примечание, как правило, заявления не являются выражениями; они не возвращают значение. Исключением, конечно же, являются операторы выражений, которые используют print и даже простые выражения, используемые в качестве операторов, такие как1; синтаксис, который PHP наследует от C. Оператор выражения может выглядеть странно, но он очень полезен, позволяя передавать аргументы функции.

Это printфункция?

Нет, это языковая конструкция. Хотя все вызовы функций являются выражениями, print (expr)это выражение, несмотря на то, что визуальный элемент выглядит так, как если бы он использовал синтаксис вызова функций. По правде говоря, эти скобки представляют собой синтаксис скобок-expr, полезный для вычисления выражений. Это объясняет тот факт, что иногда они являются необязательными, если выражение является простым, например print "Hello, world!". С более сложным выражением, таким как print (5 ** 2 + 6/2); // 28скобки, можно помочь в оценке выражения. В отличие от имен функций, printсинтаксически является ключевым словом и семантически «языковой конструкцией» .

Термин «языковая конструкция» в PHP обычно относится к «псевдо» функциям, таким как issetили empty. Хотя эти «конструкции» выглядят в точности как функции, они на самом деле являются fexprs , то есть аргументы передаются им без оценки, что требует особой обработки от компилятора. printслучается, fexpr, который выбирает для оценки своего аргумента так же, как функции.

Разницу можно увидеть по распечатке get_defined_functions(): в printсписке нет функций. (Хотя printfи друзья: в отличие от них print, они истинные функции.)

Почему print (foo) работает тогда?

По той же причине, что echo(foo)работает. Эти круглые скобки сильно отличаются от круглых скобок вызова функций, потому что вместо этого они относятся к выражениям. Вот почему можно кодировать echo ( 5 + 8 )и ожидать результата 13 (см. Ссылку ). Эти круглые скобки участвуют в оценке выражения, а не в вызове функции. Примечание: в PHP есть и другие варианты использования скобок, такие как условные выражения if, списки присваиваний, объявления функций и т. Д.

Почему print(1,2,3)и echo(1,2,3)привести к ошибкам синтаксиса?

Синтаксис есть print expr, echo exprили echo expr, expr, ..., expr. Когда PHP встречается (1,2,3), он пытается проанализировать его как одно выражение и завершается неудачно, потому что в отличие от C, PHP на самом деле не имеет двоичного оператора запятой; запятая служит в качестве разделителя. (Тем не менее, вы можете найти двоичную запятую в циклах for PHP, синтаксис которой унаследован от C.)

Семантика

Это утверждение echo e1, e2, ..., eN;можно понимать как синтаксический сахар для echo e1; echo e2; ...; echo eN;.

Поскольку все выражения являются операторами и echo eвсегда имеют те же побочные эффекты print e, что и возвращаемое значение print eигнорируется при использовании в качестве оператора, мы можем понимать его echo eкак синтаксический сахар для print e.

Эти два наблюдения означают, что echo e1, e2, ..., eN;можно рассматривать как синтаксический сахар для print e1; print e2; ... print eN;. (Тем не менее, обратите внимание на несемантические различия во время выполнения ниже.)

Поэтому нам нужно только определить семантику для print. print eпри оценке:

  1. оценивает свой единственный аргумент eи преобразует полученное значение в строку s. (Таким образом, print eэквивалентно print (string) e.)
  2. Потоки строку sв выходной буфер (который в конечном счете будет передаваться на стандартный вывод).
  3. Оценивает до целого числа 1.

Различия на уровне байт-кода

print включает небольшие накладные расходы на заполнение возвращаемой переменной (псевдокод)

print 125;

PRINT  125,$temp     ; print 125 and place 1 in $temp 
UNSET  $temp         ; remove $temp

один echoкомпилируется в один код операции:

echo 125;

ECHO 125

многозначные echoкомпилируется в несколько операционных кодов

echo 123, 456;

ECHO 123
ECHO 456

Обратите внимание, что multi-value echoне объединяет свои аргументы, а выводит их один за другим.

Справка: zend_do_print, zend_do_echo.

Различия во время выполнения

ZEND_PRINT реализован следующим образом (псевдокод)

PRINT  var, result:

    result = 1
    ECHO var

Таким образом, он в основном помещает 1переменную результата и делегирует реальную работу ZEND_ECHOобработчику. ZEND_ECHOделает следующее

ECHO var:

    if var is object
        temp = var->toString()
        zend_print_variable(temp)
    else
        zend_print_variable(var)

где zend_print_variable()выполняет фактическую «печать» (фактически она просто перенаправляет на выделенную функцию SAPI).

Скорость: echo xпротивprint x

В отличие от echo , print выделяет временную переменную. Тем не менее, количество времени, затрачиваемого на эту деятельность, незначительно, поэтому разница между этими двумя языковыми конструкциями незначительна.

Скорость: echo a,b,cпротивecho a.b.c

Первый сводится к трем отдельным утверждениям. Второй оценивает все выражение a.b.c., печатает результат и сразу же удаляет его. Поскольку объединение включает в себя распределение памяти и копирование, первый вариант будет более эффективным.

Так какой из них использовать?

В веб-приложениях вывод в основном сконцентрирован в шаблонах. Поскольку шаблоны используют <?=псевдоним echo, кажется логичным придерживаться и echoдругих частей кода. echoимеет дополнительное преимущество, заключающееся в возможности печатать несколько выражений без их объединения, и не требует дополнительных затрат на заполнение временной возвращаемой переменной. Итак, пользуйтесь echo.

user187291
источник
5
Я тщательно отредактировал и уточнил это, а также добавил раздел о семантике. Я довольно уверен в этом, но кто-то может перепроверить это.
jameshfisher
1
Значит ли это, что лучше использовать echo $a,$b,$cдля объединения строковых переменных? Честно говоря, я никогда не видел это в использовании.
Джефф
1
Как насчет раздела TL; DR, описывающего функциональные различия? Like: printпозволяет только один аргумент, echoможет иметь несколько; echoне может быть частью выражения, а printможет и возвращает ...; и может быть некоторое резюме производительности. И все эти «почему» и «под капотом» части потом
YakovL
0

Я знаю, что опоздал, но я хотел бы добавить, что в моем коде

 $stmt = mysqli_stmt_init($connection) or echo "error at init"; 

выдает ошибку «синтаксическая ошибка, неожиданное« эхо »(T_ECHO)»

пока

 $stmt = mysqli_stmt_init($connection) or print "error at init";

работает отлично.

Документы о эхе говорят «эхо ( в отличии от некоторых других языковых конструкций) не ведет себя как функция» здесь , но о печати документах также говорит , «печать не на самом деле реальная функция (это конструкция языка)» здесь . Поэтому я не уверен, почему. В документах echo и print также говорится: «Основные отличия echo в том, что print принимает только один аргумент и всегда возвращает 1». Вот

Я был бы счастлив, если бы кто-нибудь мог пролить свет на это поведение.

Махад Али
источник