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:
- ocenia pojedynczy argument
ei rzutuje uzyskaną wartość na ciąg s. (Tak więc print ejest równoważne print (string) e.)
- Przesyła strumieniowo ciąg
sdo 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 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.