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, ... expr
jest instrukcją, podczas gdy print 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:
5 + echo 6; // syntax error
Przeciwnie, print expr
moż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 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:
<?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 print
zwraca wartość, a echo
nie zwraca ?
Wyrażenia oceniają na wartości. Na przykład 2 + 3
ocenia 5
i abs(-10)
ocenia 10
. 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:
<?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); // 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
lub 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. 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 na print
liście żadnej funkcji. (Chociaż printf
i 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 expr
lub 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 e
zawsze mają takie same skutki uboczne jak print e
, a zwracana wartość print e
jest ignorowana, gdy jest używana jako instrukcja, możemy rozumieć echo e
jako 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:
- ocenia pojedynczy argument
e
i rzutuje uzyskaną wartość na ciąg s
. (Tak więc print e
jest równoważne print (string) e
.)
- Przesyła strumieniowo ciąg
s
do bufora wyjściowego (który ostatecznie zostanie przesłany strumieniowo do standardowego wyjścia).
- 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 echo
kompilacje do jednego kodu operacji:
echo 125;
ECHO 125
wiele wartości echo
kompiluje się do wielu kodów
echo 123, 456;
ECHO 123
ECHO 456
Zauważ, ż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)
PRINT var, result:
result = 1
ECHO var
Zasadniczo umieszcza 1
więc zmienną wynikową i przekazuje prawdziwe zadanie do modułu ZEND_ECHO
obsługi. ZEND_ECHO
wykonuje 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 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ą aliasami echo
, 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żyj echo
.