Odniesienie: Porównanie wydruku i echa PHP


182

Jaka jest różnica między PHP printa echo?

Przepełnienie stosu ma wiele pytań dotyczących użycia PHP printi echosłów kluczowych.

Celem tego postu jest udzielenie kanonicznego pytania referencyjnego i odpowiedzi na temat PHP printi echosłów kluczowych oraz porównanie ich różnic i przypadków użycia.


3
Myślę, że tutaj nie wystarczy o wartości zwracanej przez druk. Polecenie print jest przydatne do szybkiego debugowania lub czegoś podobnego: strpos ($ x, $ y)! == FAŁSZ LUB wydrukuj „coś”. Szybki do pisania i czytelny. A „Czy wydrukować funkcję” z jakiegoś powodu było niewygodne (twoja argumentacja wydaje się ... dziwna i nieoczywista) - jest to konstrukcja językowa, jest o wiele gorsza rzecz, której nie możesz z tym zrobić: funkcje zmiennych.
XzKto,

1
Aby zachować tę otwartość, należy tutaj: 1. podzielić na pytanie i odpowiedź. 2. Odwołanie / link do istniejącej treści na temat przepełnienia stosu (trochę jak tutaj: stackoverflow.com/questions/3737139/... ), ale w odpowiedzi. 3. Musi być CW.
Kev

„Powiązana kolumna” jest w porządku, ale nie jest bardzo skoncentrowana. Aby zwiększyć jego wartość jako kanoniczne pytanie referencyjne i odpowiedź, należy ją również dobrze zbadać, a linki do innych konkretnych dobrych odpowiedzi przyniosłyby wartość dodaną.
Kev

Pytanie naprawdę musi być prawdziwym pytaniem . Mogę dodać banner dotyczący części kanonicznej, kiedy skończysz.
Tim Post

Odpowiedzi:


185

Dlaczego dwie konstrukcje?

Prawda o drukowaniu i echu jest taka, że ​​chociaż wydają się użytkownikom jako dwie odrębne konstrukcje, oba są naprawdę odcieniami echa, jeśli przejdziesz do podstaw, tj. Spojrzysz na wewnętrzny kod źródłowy. Ten kod źródłowy obejmuje analizator składni, a także moduły obsługi kodów. Rozważ proste działanie, takie jak wyświetlenie liczby zero. Bez względu na to, czy używasz echa, czy drukowania, zostanie wywołany ten sam moduł obsługi „ZEND_ECHO_SPEC_CONST_HANDLER”. Procedura obsługi print wykonuje jedną czynność, zanim wywoła procedurę obsługi echa, upewnia się, że zwracana wartość print wynosi 1, w następujący sposób:

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

(patrz tutaj w celach informacyjnych )

Zwracana wartość jest wygodą, jeśli chce się używać print w wyrażeniu warunkowym. Dlaczego 1, a nie 100? Cóż, w PHP prawdziwość 1 lub 100 jest taka sama, tj. Prawda, podczas gdy 0 w kontekście logicznym jest równe wartości fałszywej. W PHP wszystkie niezerowe wartości (dodatnie i ujemne) są prawdziwymi wartościami, a wywodzi się to ze spuścizny języka Perl w PHP.

Ale jeśli tak jest, to można się zastanawiać, dlaczego echo bierze wiele argumentów, podczas gdy print może obsłużyć tylko jeden. Aby uzyskać tę odpowiedź, musimy przejść do analizatora składni, a konkretnie do pliku zend_language_parser.y . Zauważysz, że echo ma wbudowaną elastyczność, dzięki czemu może drukować jedno lub wiele wyrażeń (patrz tutaj ). podczas gdy print jest ograniczone do drukowania tylko jednego wyrażenia (patrz tam ).

Składnia

W języku programowania C i językach, na które ma on wpływ, takich jak PHP, istnieje rozróżnienie między instrukcjami i wyrażeniami. Składniowo, echo expr, expr, ... exprjest instrukcją, podczas gdy print exprjest wyrażeniem, ponieważ zwraca wartość. Dlatego, podobnie jak inne stwierdzenia, echo exprjest samodzielny i nie może zostać uwzględniony w wyrażeniu:

5 + echo 6;   // syntax error

Przeciwnie, print exprmoże samodzielnie sformułować oświadczenie:

print 5; // valid

Lub bądź częścią wyrażenia:

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

Jeden może być skłonny myśleć print, jak gdyby był to operator jednoargumentowy, jak !czy ~jednak nie jest operatorem. Ich !, ~ and printwspólną cechą jest to, że wszystkie są wbudowane w PHP i każdy wymaga tylko jednego argumentu. Możesz użyć printdo utworzenia następującego dziwnego, ale poprawnego kodu:

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

Na pierwszy rzut oka wynik może wydawać się dziwny, że ostatnie polecenie drukowania najpierw wypisuje swój argument „7” . Ale jeśli kopiesz głębiej i spojrzysz na rzeczywiste kody, ma to sens:

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

Pierwszym generowanym kodem operacji jest kod odpowiadający „print 7”. „~ 0” jest zmienną tymczasową, której wartość wynosi 1. Ta zmienna staje się operandem dla następnego kodu operacji drukowania, który z kolei zwraca zmienną tymczasową i proces się powtarza. Ostatnia zmienna tymczasowa w ogóle nie jest używana, więc zostaje uwolniona.

Dlaczego printzwraca wartość, a echonie zwraca ?

Wyrażenia oceniają na wartości. Na przykład 2 + 3ocenia 5i abs(-10)ocenia 10. Ponieważ print exprsamo w sobie jest wyrażeniem, powinno zawierać wartość i tak jest, spójna wartość 1wskazuje prawdziwy wynik, a zwracając wartość niezerową, wyrażenie staje się przydatne do włączenia do innego wyrażenia. Na przykład w tym fragmencie wartość zwracana przez print jest przydatna do określania sekwencji funkcji:

<?php

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

if ( foo() ) {

     bar();
}

Możesz znaleźć wydruk o szczególnej wartości, jeśli chodzi o debugowanie w locie, jak pokazuje następny przykład:

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

// output: f not in abcde

Na marginesie, ogólnie stwierdzenia nie są wyrażeniami; nie zwracają wartości. Wyjątkiem są oczywiście instrukcje wyrażeń, które używają print, a nawet proste wyrażenia używane jako instrukcje, takie jak1; składnia, którą PHP dziedziczy z C. Wyrażenie wyrażenia może wyglądać dziwnie, ale jest bardzo pomocne, umożliwiając przekazanie argumentów do Funkcje.

Jest print funkcją?

Nie, to konstrukcja językowa. Podczas gdy wszystkie wywołania funkcji są wyrażeniami, print (expr)jest wyrażeniem, mimo że wygląda na to, jakby używało składni wywołania funkcji. W rzeczywistości nawiasy te są składnią nawiasów-wyrażów, przydatną do oceny wyrażeń. To wyjaśnia fakt, że czasami są one opcjonalne, jeśli wyrażenie jest proste, takie jak print "Hello, world!". Bardziej złożone wyrażenie, takie jak print (5 ** 2 + 6/2); // 28nawiasy, pomaga w ocenie wyrażenia. W przeciwieństwie do nazw funkcji, printjest składniowo słowem kluczowym , a semantycznie „konstrukcją językową” .

Termin „konstrukcja języka” w PHP zwykle odnosi się do funkcji „pseudo”, takich jak issetlub empty. Chociaż te „konstrukcje” wyglądają dokładnie jak funkcje, w rzeczywistości są one fexprs , to znaczy argumenty są przekazywane do nich bez oceny, co wymaga specjalnego traktowania od kompilatora. printokazuje się być fexpr, który wybiera oceniać swój argument w taki sam sposób, jak funkcję.

Różnicę widać po wydrukowaniu get_defined_functions(): nie ma na printliście żadnej funkcji. (Chociaż printfi przyjaciele są: w przeciwieństwie do print, są prawdziwymi funkcjami.)

Dlaczego zatem działa print (foo)?

Z tego samego powodu, który echo(foo)działa. Nawiasy te różnią się od nawiasów wywołań funkcji, ponieważ odnoszą się do wyrażeń. Dlatego można kodować echo ( 5 + 8 )i oczekiwać wyniku 13 do wyświetlenia (patrz odnośnik ). Nawiasy te służą do oceny wyrażenia, a nie do wywoływania funkcji. Uwaga: istnieją inne zastosowania nawiasów w PHP, takie jak wyrażenia warunkowe if, listy przypisań, deklaracje funkcji itp.

Dlaczego print(1,2,3)i echo(1,2,3)spowodować błędy składni?

Składnia to print expr, echo exprlub echo expr, expr, ..., expr. Kiedy PHP napotyka(1,2,3) , próbuje go parsować jako pojedyncze wyrażenie i kończy się niepowodzeniem, ponieważ w przeciwieństwie do C, PHP tak naprawdę nie ma binarnego operatora przecinka; przecinek służy bardziej jako separator. (Możesz jednak znaleźć przecinek binarny w pętlach for PHP, składnia została odziedziczona z C.)

Semantyka

Stwierdzenie echo e1, e2, ..., eN;to można rozumieć jako cukier składniowy dla echo e1; echo e2; ...; echo eN;.

Ponieważ wszystkie wyrażenia są instrukcjami i echo ezawsze mają takie same skutki uboczne jak print e, a zwracana wartość print ejest ignorowana, gdy jest używana jako instrukcja, możemy rozumieć echo ejako cukier składniowy print e.

Te dwie obserwacje oznaczają, że echo e1, e2, ..., eN;można to uznać za cukier składniowy print e1; print e2; ... print eN;. (Należy jednak zwrócić uwagę na różnice w semestrze wykonawczym poniżej).

Dlatego musimy tylko zdefiniować semantykę print. print e, po ocenie:

  1. ocenia pojedynczy argument ei rzutuje uzyskaną wartość na ciąg s. (Tak więc print ejest równoważne print (string) e.)
  2. Przesyła strumieniowo ciąg sdo bufora wyjściowego (który ostatecznie zostanie przesłany strumieniowo do standardowego wyjścia).
  3. Oblicza do liczby całkowitej 1.

Różnice na poziomie kodu bajtowego

print wymaga niewielkiego narzutu zapełniania zmiennej zwracanej (pseudokod)

print 125;

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

pojedyncze echokompilacje do jednego kodu operacji:

echo 125;

ECHO 125

wiele wartości echokompiluje się do wielu kodów

echo 123, 456;

ECHO 123
ECHO 456

Zauważ, że wielowartościowy echonie łączy swoich argumentów, ale wypisuje je jeden po drugim.

Odniesienie: zend_do_print, zend_do_echo.

Różnice w czasie wykonywania

ZEND_PRINT jest implementowany w następujący sposób (pseudokod)

PRINT  var, result:

    result = 1
    ECHO var

Zasadniczo umieszcza 1więc zmienną wynikową i przekazuje prawdziwe zadanie do modułu ZEND_ECHOobsługi. ZEND_ECHOwykonuje następujące czynności

ECHO var:

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

gdzie zend_print_variable()wykonuje rzeczywiste „drukowanie” (w rzeczywistości jedynie przekierowuje do dedykowanej funkcji SAPI).

Prędkość: echo xvsprint x

W przeciwieństwie do echa , print przydziela zmienną tymczasową. Jednak czas poświęcony na tę aktywność jest niewielki, więc różnica między tymi dwoma konstrukcjami językowymi jest znikoma.

Prędkość: echo a,b,cvsecho a.b.c

Pierwszy kompiluje do trzech oddzielnych instrukcji. Drugi ocenia całe wyrażenie a.b.c., drukuje wynik i usuwa go natychmiast. Ponieważ konkatenacja obejmuje przydzielanie pamięci i kopiowanie, pierwsza opcja będzie bardziej wydajna.

Którego użyć?

W aplikacjach internetowych dane wyjściowe są głównie skoncentrowane w szablonach. Ponieważ używane są szablony <?=, które są aliasami echo, logiczne wydaje się trzymanie się również echoinnych części kodu. echoma tę dodatkową zaletę, że może drukować wiele wyrażeń bez łączenia ich i nie wymaga nakładania na tymczasową zmienną zwracaną. Więc użyj echo.


5
Dokładnie to zredagowałem i wyjaśniłem, a także dodałem sekcję dotyczącą semantyki. Jestem dość pewny, ale ktoś mógłby to sprawdzić dwukrotnie.
jameshfisher,

1
Czy to znaczy, że lepiej jest używać echo $a,$b,$cdo łączenia łańcuchów zmiennych? Szczerze mówiąc, nigdy nie widziałem tego w użyciu.
geoff

1
Co powiesz na sekcję TL; DR opisującą różnice funkcjonalne? Jak: printdopuszcza tylko jeden argument, echomoże mieć wiele; echonie może być częścią wyrażenia, póki printmoże i zwraca ...; i może być jakieś podsumowanie wydajności. A wszystkie te „dlaczego” i „pod maską” części potem
JakowL,

0

Wiem, że się spóźniłem, ale chciałbym dodać to, że w moim kodzie

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

daje błąd „błąd składni, nieoczekiwane„ echo ”(T_ECHO)”

podczas

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

działa w porządku.

Dokumenty dotyczące echa mówią, że „echo (w przeciwieństwie do innych konstrukcji językowych) nie zachowuje się tutaj jak funkcja” , ale w przypadku dokumentów drukowanych mówi także, że „druk nie jest tak naprawdę funkcją (jest konstrukcją językową)” tutaj . Więc nie jestem pewien dlaczego. A także o echu i drukowaniu dokumentów mówi: „Główne różnice w echu polegają na tym, że print przyjmuje tylko jeden argument i zawsze zwraca 1”. tutaj

Byłbym szczęśliwy, gdyby ktokolwiek mógł rzucić nieco światła na to zachowanie.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.