Neden iki yapı?
Baskı ve yankı hakkındaki gerçek , kullanıcılara iki farklı yapı olarak görünseler de, temellere inerseniz, yani dahili kaynak koduna baktığınızda, her ikisi de gerçekten yankı tonlarıdır. Bu kaynak kodu ayrıştırıcıyı ve opcode işleyicilerini içerir. Sıfır sayısını görüntülemek gibi basit bir işlemi düşünün. Yankı veya baskı kullansanız da, aynı işleyici "ZEND_ECHO_SPEC_CONST_HANDLER" çağrılır. Yazdırma işleyicisi yankı için işleyiciyi çağırmadan önce bir şey yapar, yazdırma için dönüş değerinin aşağıdaki gibi 1 olduğundan emin olur:
ZVAL_LONG(&EX_T(opline->result.var).tmp_var, 1);
( referans için buraya bakınız )
Dönüş değeri, koşullu ifadede baskıyı kullanmak isteyen bir kolaylıktır. Neden 1 değil 100? PHP'de 1 veya 100'ün doğruluğu aynıdır, yani doğrudur, oysa boolean bağlamında 0 yanlış bir değere eşittir. PHP'de sıfır olmayan tüm değerler (pozitif ve negatif) gerçeğe uygun değerlerdir ve bu PHP'nin Perl mirasından kaynaklanır.
Ancak, eğer durum buysa, o zaman echo neden birden fazla argüman alırken, baskı sadece bir tanesini işleyebilir. Bu cevap için ayrıştırıcıya, özellikle de zend_language_parser.y dosyasına dönmemiz gerekiyor . Echo'nun bir veya daha fazla ifade yazabilmesi için yerleşik esnekliğe sahip olduğunu göreceksiniz ( buraya bakın ). oysa baskı yalnızca bir ifade basmaya sınırlıdır ( oraya bakınız ).
Sözdizimi
C programlama dilinde ve PHP gibi etkilenen dillerde, ifadeler ve ifadeler arasında bir ayrım vardır. Sözdizimsel olarak, bir değer olarak değerlendirildiği için echo expr, expr, ... expr
while print expr
ifadesidir. Bu nedenle, diğer ifadeler gibi echo expr
, kendi başına durur ve bir ifadeye dahil edilemez:
5 + echo 6; // syntax error
Aksine, print expr
tek başına bir ifade oluşturabilir:
print 5; // valid
Veya bir ifadenin parçası olun:
$x = (5 + print 5); // 5
var_dump( $x ); // 6
Kişi print
, sanki bir operatör gibi !
ya da ~
bir operatör gibi düşünülmeyebilir . Ne !, ~ and print
ortak noktası hepsinin PHP yerleşik olarak ve her tek bir argüman alır olmasıdır. print
Aşağıdaki garip ama geçerli kodu oluşturmak için kullanabilirsiniz :
<?php
print print print print 7; // 7111
İlk bakışta sonuç, son baskı ifadesinin ilk olarak '7' operandını yazdırması tuhaf görünebilir . Ancak, daha derine iner ve gerçek opcode bakarsanız, mantıklı:
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
Üretilen ilk opcode 'baskı 7'ye karşılık gelen koddur. '~ 0' değeri 1 olan geçici bir değişkendir. Bu değişken bir sonraki yazdırma opkodu için olur ve işlenir, bu da geçici bir değişken döndürür ve işlem tekrarlanır. Son geçici değişken hiç kullanılmaz, bu yüzden serbest kalır.
Neden print
bir değer döndürüyor ve echo
vermiyor?
İfadeler değerlere göre değerlendirilir. Örneğin , 2 + 3
değerini 5
ve abs(-10)
değerini değerlendirir 10
. Bu yana print expr
bir ekspresyon kendisi, o zaman bir değer sahip olmalıdır ve bu, tutarlı bir değeri de 1
bir truthy sonucunu gösterir ve ifade bir ifade dahil edilmesi için yararlı olur, sıfır olmayan bir değer iade ile. Örneğin bu snippet'te, baskının dönüş değeri bir işlev sırası belirlemede yararlıdır:
<?php
function bar( $baz ) {
// other code
}
function foo() {
return print("In and out ...\n");
}
if ( foo() ) {
bar();
}
Sonraki örnekte gösterildiği gibi, hata ayıklama söz konusu olduğunda belirli bir değerin baskısını bulabilirsiniz:
<?php
$haystack = 'abcde';
$needle = 'f';
strpos($haystack,$needle) !== FALSE OR print "$needle not in $haystack";
// output: f not in abcde
Bir yan not olarak, genellikle ifadeler ifade değildir; bir değer döndürmezler. İstisna, elbette, 1;
PHP'yi C'den devraldığı bir sözdizimi gibi baskı ve hatta ifade olarak kullanılan basit ifadeleri kullanan ifade ifadeleridir. İfade ifadesi tuhaf görünebilir, ancak argümanları iletmeyi mümkün kılar. fonksiyonlar.
Mı print
bir işlev?
Hayır, bir dil kurgusu. Tüm işlev çağrıları ifadeler print (expr)
olsa da, işlev çağrısı sözdizimi kullanıyormuş gibi görünen görsele rağmen bir ifadedir. Gerçekte bu parantezler, ifade değerlendirmesi için yararlı olan parantez-ifade sözdizimidir. Bu, ifadenin basit bir ifadesi olduğu durumlarda zaman zaman isteğe bağlı oldukları gerçeğini açıklar print "Hello, world!"
. print (5 ** 2 + 6/2); // 28
Parantez gibi daha karmaşık bir ifade ile ifadenin değerlendirilmesine yardımcı olur. İşlev adlarının aksine print
, sözdizimsel olarak bir anahtar kelime ve anlamsal olarak bir "dil yapısı" dır .
PHP'deki "dil yapısı" terimi genellikle isset
veya gibi "sözde" işlevlere karşılık gelir empty
. Bu "yapılar" tam olarak işlevler gibi görünseler de , gerçekte feksprlerdir , yani argümanlar değerlendirilmeden onlara aktarılır, bu da derleyiciden özel bir işlem gerektirir. print
argümanını bir işlevle aynı şekilde değerlendirmeyi seçen bir fekspr olur.
Fark yazdırılarak görülebilir get_defined_functions()
: print
listelenen işlev yok . (Rağmen printf
ve arkadaşlar: aksine print
, onlar gerçek işlevler.)
O halde baskı (foo) neden çalışır?
Aynı nedenden dolayı echo(foo)
çalışır. Bu parantezler işlev çağrısı parantezlerinden oldukça farklıdır, çünkü bunun yerine ifadelerle ilgilidirler. Bu yüzden kodlama echo ( 5 + 8 )
yapılabilir ve 13 sonucunun görüntülenmesini bekleyebilir ( referansa bakın ). Bu parantez, bir işlevi çağırmak yerine bir ifadeyi değerlendirmekle ilgilidir. Not: PHP'de parantez için if-koşullu ifadeler, atama listeleri, işlev bildirimleri vb. Gibi başka kullanımlar da vardır.
Neden print(1,2,3)
ve echo(1,2,3)
sözdizimi hatalarına neden?
Sözdizimi print expr
, echo expr
ya echo expr, expr, ..., expr
. PHP karşılaştığında (1,2,3)
, bunu tek bir ifade olarak ayrıştırmaya çalışır ve başarısız olur, çünkü C'nin aksine, PHP'nin gerçekten bir ikili virgül operatörü yoktur; virgül daha çok ayırıcı görevi görür. (Yine de PHP'nin döngülerinde ikili bir virgül bulabilirsiniz, sözdizimi C'den miras alınmıştır)
semantik
İfadesi echo e1, e2, ..., eN;
için sözdizimsel şeker gibi anlaşılabilir echo e1; echo e2; ...; echo eN;
.
Tüm ifadeler ifadeler olduğundan ve echo e
her zaman aynı yan etkilere sahip print e
olduğundan ve print e
ifadesi olarak kullanıldığında dönüş değeri göz ardı edildiğinden echo e
sözdizimsel şeker olarak anlayabiliriz print e
.
Bu iki gözlem echo e1, e2, ..., eN;
, sözdizimsel şeker olarak görülebileceği anlamına gelir print e1; print e2; ... print eN;
. (Ancak, aşağıda semantik olmayan çalışma zamanı farklılıklarına dikkat edin.)
Bu nedenle, sadece semantiği tanımlamamız gerekir print
. print e
, değerlendirildiğinde:
- Bunu tek bir bağımsız değişken değerlendirir
e
ve tip-atan bir dizi elde edilen değer s
. (Böylece, print e
eşdeğerdir print (string) e
.)
- Dizeyi Akımlar
s
için çıkış tamponu (sonunda standart çıkışa akışı yayınlanmayacaktır).
- Tamsayıyı değerlendirir
1
.
Bayt kodu düzeyindeki farklılıklar
print
dönüş değişkenini doldurmanın küçük bir ek yükünü içerir (sözde kod)
print 125;
PRINT 125,$temp ; print 125 and place 1 in $temp
UNSET $temp ; remove $temp
tek echo
bir opcode derler:
echo 125;
ECHO 125
çok değerli echo
çoklu kodları derler
echo 123, 456;
ECHO 123
ECHO 456
Çoklu değerin echo
bağımsız değişkenlerini birleştirmediğini, ancak bunları teker teker çıkardığını unutmayın .
Referans: zend_do_print
, zend_do_echo
.
Çalışma zamanı farklılıkları
ZEND_PRINT
aşağıdaki gibi uygulanır (sözde kod)
PRINT var, result:
result = 1
ECHO var
Temelde 1
sonuç değişkenini koyar ve gerçek işi ZEND_ECHO
işleyiciye devreder . ZEND_ECHO
aşağıdakileri yapar
ECHO var:
if var is object
temp = var->toString()
zend_print_variable(temp)
else
zend_print_variable(var)
burada zend_print_variable()
gerçek "yazdırma" işlevini gerçekleştirir (aslında yalnızca özel bir SAPI işlevine yönlendirir).
Hız: echo x
vsprint x
Aksine yankı , baskı geçici bir değişken ayırır. Bununla birlikte, bu etkinlik için harcanan zaman çok küçüktür, bu nedenle bu iki dil yapısı arasındaki fark göz ardı edilebilir.
Hız: echo a,b,c
vsecho a.b.c
İlki üç ayrı ifadeyi derler. İkincisi tüm ifadeyi değerlendirir, a.b.c.
sonucu yazdırır ve hemen atar. Birleştirme bellek ayırmalarını ve kopyalamayı içerdiğinden, ilk seçenek daha verimli olacaktır.
Peki hangisini kullanmalıyım?
Web uygulamalarında, çıktı çoğunlukla şablonlarda yoğunlaşır. Şablonlar <?=
, takma adı olan kullandığından , kodun diğer kısımlarına da bağlı kalmak echo
mantıklı görünüyor echo
. echo
birden çok ifadeyi birleştirmeden yazdırabilmesinin ek bir avantajı vardır ve geçici bir dönüş değişkenini doldurma yükünü içermez. Yani, kullanın echo
.