Jaka jest różnica między PHP print
a echo
?
Przepełnienie stosu ma wiele pytań dotyczących użycia PHP print
i echo
słów kluczowych.
Celem tego postu jest udzielenie kanonicznego pytania referencyjnego i odpowiedzi na temat PHP print
i echo
słów kluczowych oraz porównanie ich różnic i przypadków użycia.
Odpowiedzi:
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:
(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, ... expr
jest instrukcją, podczas gdyprint expr
jest wyrażeniem, ponieważ zwraca wartość. Dlatego, podobnie jak inne stwierdzenia,echo expr
jest samodzielny i nie może zostać uwzględniony w wyrażeniu:Przeciwnie,
print expr
może samodzielnie sformułować oświadczenie:Lub bądź częścią wyrażenia:
Jeden może być skłonny myśleć
print
, jak gdyby był to operator jednoargumentowy, jak!
czy~
jednak nie jest operatorem. Ich!, ~ and print
wspólną cechą jest to, że wszystkie są wbudowane w PHP i każdy wymaga tylko jednego argumentu. Możesz użyćprint
do utworzenia następującego dziwnego, ale poprawnego kodu: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:
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
print
zwraca wartość, aecho
nie zwraca ?Wyrażenia oceniają na wartości. Na przykład
2 + 3
ocenia5
iabs(-10)
ocenia10
. Ponieważprint expr
samo w sobie jest wyrażeniem, powinno zawierać wartość i tak jest, spójna wartość1
wskazuje 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:Możesz znaleźć wydruk o szczególnej wartości, jeśli chodzi o debugowanie w locie, jak pokazuje następny przykład:
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 jak
1;
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 jakprint "Hello, world!"
. Bardziej złożone wyrażenie, takie jakprint (5 ** 2 + 6/2); // 28
nawiasy, pomaga w ocenie wyrażenia. W przeciwieństwie do nazw funkcji,print
jest składniowo słowem kluczowym , a semantycznie „konstrukcją językową” .Termin „konstrukcja języka” w PHP zwykle odnosi się do funkcji „pseudo”, takich jak
isset
lubempty
. 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.print
okazuje 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 naprint
liście żadnej funkcji. (Chociażprintf
i przyjaciele są: w przeciwieństwie doprint
, 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)
iecho(1,2,3)
spowodować błędy składni?Składnia to
print expr
,echo expr
lubecho 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 dlaecho e1; echo e2; ...; echo eN;
.Ponieważ wszystkie wyrażenia są instrukcjami i
echo e
zawsze mają takie same skutki uboczne jakprint e
, a zwracana wartośćprint e
jest ignorowana, gdy jest używana jako instrukcja, możemy rozumiećecho e
jako cukier składniowyprint e
.Te dwie obserwacje oznaczają, że
echo e1, e2, ..., eN;
można to uznać za cukier składniowyprint 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:e
i rzutuje uzyskaną wartość na ciągs
. (Tak więcprint e
jest równoważneprint (string) e
.)s
do bufora wyjściowego (który ostatecznie zostanie przesłany strumieniowo do standardowego wyjścia).1
.Różnice na poziomie kodu bajtowego
print
wymaga niewielkiego narzutu zapełniania zmiennej zwracanej (pseudokod)pojedyncze
echo
kompilacje do jednego kodu operacji:wiele wartości
echo
kompiluje się do wielu kodówZauważ, że wielowartościowy
echo
nie łą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)Zasadniczo umieszcza
1
więc zmienną wynikową i przekazuje prawdziwe zadanie do modułuZEND_ECHO
obsługi.ZEND_ECHO
wykonuje następujące czynnościgdzie
zend_print_variable()
wykonuje rzeczywiste „drukowanie” (w rzeczywistości jedynie przekierowuje do dedykowanej funkcji SAPI).Prędkość:
echo x
vsprint 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,c
vsecho 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ą aliasamiecho
, logiczne wydaje się trzymanie się równieżecho
innych części kodu.echo
ma 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żyjecho
.źródło
echo $a,$b,$c
do łączenia łańcuchów zmiennych? Szczerze mówiąc, nigdy nie widziałem tego w użyciu.print
dopuszcza tylko jeden argument,echo
może mieć wiele;echo
nie może być częścią wyrażenia, pókiprint
może i zwraca ...; i może być jakieś podsumowanie wydajności. A wszystkie te „dlaczego” i „pod maską” części potemWiem, że się spóźniłem, ale chciałbym dodać to, że w moim kodzie
daje błąd „błąd składni, nieoczekiwane„ echo ”(T_ECHO)”
podczas
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.
źródło