Referensi: Membandingkan cetak dan gema PHP

182

Apa perbedaan antara PHP printdan echo?

Stack Overflow memiliki banyak pertanyaan tentang penggunaan PHP printdan echokata kunci.

Tujuan dari posting ini adalah untuk memberikan pertanyaan dan jawaban referensi kanonik tentang PHP printdan echokata kunci dan membandingkan perbedaan dan kasus penggunaannya.

pengguna187291
sumber
3
Saya pikir di sini tidak cukup tentang mencetak nilai pengembalian. Cetak berguna untuk hasil debug cepat atau semacamnya: strpos ($ x, $ y)! == SALAH ATAU cetak "sesuatu". Cepat mengetik dan enak dibaca. Dan "Apakah mencetak fungsi" adalah canggung untuk membaca karena beberapa alasan (argumen Anda tampaknya ... aneh dan tidak jelas) - itu adalah konstruksi bahasa, ada hal yang jauh lebih buruk yang tidak dapat Anda lakukan dengan itu: fungsi variabel.
XzKto
1
Agar ini tetap terbuka, apa yang perlu dilakukan di sini adalah: 1. membaginya menjadi pertanyaan dan jawaban. 2. Referensi / tautan ke konten yang ada tentang materi pelajaran tentang Stack Overflow (agak seperti di sini: stackoverflow.com/questions/3737139/… ) tetapi dalam jawabannya. 3. Harus CW.
Kev
"Kolom Terkait" baik-baik saja, tetapi tidak terlalu fokus. Untuk meningkatkan nilainya sebagai pertanyaan dan jawaban referensi kanonik, maka itu juga harus diteliti dengan baik dan tautan ke jawaban baik lainnya yang spesifik akan menambah nilai.
Kev
Pertanyaannya benar-benar harus menjadi pertanyaan aktual . Saya dapat menambahkan spanduk tentang bagian kanonik setelah Anda selesai.
Pos Tim

Jawaban:

185

Mengapa dua konstruksi?

Kebenaran tentang cetak dan gema adalah bahwa meskipun mereka tampak oleh pengguna sebagai dua konstruksi berbeda, keduanya sama-sama bernuansa gema jika Anda sampai pada dasar-dasarnya, yaitu melihat kode sumber internal. Kode sumber itu melibatkan parser serta penangan opcode. Pertimbangkan tindakan sederhana seperti menampilkan angka nol. Apakah Anda menggunakan gema atau cetak, penangan yang sama "ZEND_ECHO_SPEC_CONST_HANDLER" akan dipanggil. Pawang untuk mencetak melakukan satu hal sebelum memanggil pawang untuk gema, ia memastikan bahwa nilai balik untuk cetakan adalah 1, sebagai berikut:

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

(lihat di sini untuk referensi )

Nilai baliknya adalah kenyamanan jika seseorang ingin menggunakan cetakan dalam ekspresi bersyarat. Kenapa 1 dan bukan 100? Baik di PHP kebenaran dari 1 atau 100 adalah sama, yaitu benar, sedangkan 0 dalam konteks boolean sama dengan nilai yang salah. Dalam PHP semua nilai bukan nol (positif dan negatif) adalah nilai kebenaran dan ini berasal dari warisan Perl PHP.

Tapi, jika ini masalahnya, maka orang mungkin bertanya-tanya mengapa gema mengambil beberapa argumen sedangkan cetak hanya dapat menangani satu. Untuk jawaban ini kita perlu beralih ke parser, khususnya file zend_language_parser.y . Anda akan mencatat bahwa echo memiliki fleksibilitas bawaan sehingga dapat mencetak satu atau beberapa ekspresi (lihat di sini ). sedangkan cetak dibatasi untuk mencetak hanya satu ekspresi (lihat di sana ).

Sintaksis

Dalam bahasa pemrograman C dan bahasa yang dipengaruhi olehnya seperti PHP, ada perbedaan antara pernyataan dan ekspresi. Secara sintaksis, echo expr, expr, ... expradalah pernyataan sementara print expradalah ekspresi karena ia mengevaluasi suatu nilai. Oleh karena itu, seperti pernyataan lainnya, echo exprberdiri sendiri dan tidak mampu dimasukkan dalam ekspresi:

5 + echo 6;   // syntax error

Sebaliknya,, print exprdapat sendirian membentuk pernyataan:

print 5; // valid

Atau, jadilah bagian dari ekspresi:

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

Seseorang mungkin tergoda untuk berpikir printseolah-olah itu adalah operator yang tidak waspada, seperti !atau ~bagaimanapun bukan operator. Apa yang !, ~ and printsama adalah bahwa mereka semua dibangun ke dalam PHP dan masing-masing hanya membutuhkan satu argumen. Anda dapat menggunakan printuntuk membuat kode aneh tapi valid berikut:

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

Pada pandangan pertama hasilnya mungkin tampak aneh bahwa pernyataan cetak terakhir mencetak operan dari '7' pertama . Tetapi, jika Anda menggali lebih dalam dan melihat opcodes yang sebenarnya masuk akal:

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

Opcode pertama yang dihasilkan adalah yang sesuai dengan 'print 7'. '~ 0' adalah variabel sementara yang nilainya 1. Variabel itu menjadi dan operan untuk opcode cetak berikutnya yang pada gilirannya mengembalikan variabel sementara dan proses berulang. Variabel sementara terakhir tidak digunakan sama sekali jadi, itu akan dibebaskan.

Mengapa printmengembalikan nilai dan echotidak?

Ekspresi mengevaluasi nilai. Misalnya 2 + 3mengevaluasi ke 5, dan abs(-10)mengevaluasi ke 10. Karena print expritu sendiri merupakan ekspresi, maka ia harus memiliki nilai dan itu memang, nilai yang konsisten 1menunjukkan hasil yang benar dan dengan mengembalikan nilai yang tidak nol ekspresi menjadi berguna untuk dimasukkan dalam ekspresi lain. Misalnya dalam cuplikan ini, nilai pengembalian cetak berguna dalam menentukan urutan fungsi:

<?php

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

if ( foo() ) {

     bar();
}

Anda mungkin menemukan hasil cetak dengan nilai tertentu ketika melakukan debug dengan cepat, seperti contoh berikut menggambarkan:

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

// output: f not in abcde

Sebagai catatan tambahan, umumnya, pernyataan bukan ekspresi; mereka tidak mengembalikan nilai. Pengecualian, tentu saja adalah pernyataan ekspresi yang menggunakan cetak dan bahkan ekspresi sederhana yang digunakan sebagai pernyataan, seperti1; , sintaksis yang diwariskan PHP dari C. Pernyataan ekspresi mungkin terlihat aneh tetapi sangat membantu, sehingga memungkinkan untuk meneruskan argumen ke fungsi.

Apakah printsuatu fungsi?

Tidak, ini adalah konstruksi bahasa. Sementara semua panggilan fungsi adalah ekspresi, print (expr)adalah ekspresi, meskipun visual yang muncul seolah-olah menggunakan sintaks panggilan fungsi. Sebenarnya tanda kurung ini adalah sintaks tanda kurung-expr, berguna untuk evaluasi ekspresi. Itu menjelaskan fakta bahwa kadang-kadang mereka opsional jika ekspresi itu sederhana, seperti print "Hello, world!". Dengan ekspresi yang lebih kompleks seperti print (5 ** 2 + 6/2); // 28tanda kurung membantu evaluasi ekspresi. Tidak seperti nama fungsi, printsecara sintaksis kata kunci , dan secara semantik merupakan "konstruksi bahasa" .

Istilah "konstruksi bahasa" dalam PHP biasanya merujuk pada fungsi "pseudo" seperti issetatau empty. Meskipun "konstruksi" ini terlihat persis seperti fungsi, mereka sebenarnya adalah fexprs , yaitu argumen yang diteruskan kepada mereka tanpa dievaluasi, yang memerlukan perlakuan khusus dari kompiler. printkebetulan menjadi fexpr yang memilih untuk mengevaluasi argumennya dengan cara yang sama sebagai fungsi.

Perbedaannya dapat dilihat dengan mencetak get_defined_functions(): tidak ada printfungsi yang terdaftar. (Padahal printfdan teman adalah: tidak seperti print, mereka adalah fungsi sebenarnya.)

Mengapa print (foo) berfungsi saat itu?

Untuk alasan yang sama itu echo(foo)berhasil. Tanda kurung ini sangat berbeda dari tanda kurung fungsi karena mereka berkaitan dengan ekspresi. Itulah sebabnya seseorang dapat mengkodekan echo ( 5 + 8 )dan dapat mengharapkan hasil 13 untuk ditampilkan (lihat referensi ). Tanda kurung ini terlibat dalam mengevaluasi ekspresi daripada memanggil fungsi. Catatan: ada kegunaan lain untuk tanda kurung di PHP, seperti jika if-conditional expressions, daftar tugas, deklarasi fungsi, dll.

Mengapa melakukan print(1,2,3)dan echo(1,2,3)menghasilkan kesalahan sintaksis?

Sintaksnya adalah print expr, echo expratau echo expr, expr, ..., expr. Ketika PHP bertemu (1,2,3), ia mencoba untuk menguraikannya sebagai ekspresi tunggal dan gagal, karena tidak seperti C, PHP tidak benar-benar memiliki operator koma biner; koma lebih berfungsi sebagai pemisah. (Anda dapat menemukan koma biner dalam for-loop PHP, sintaksisnya diwarisi dari C.)

Semantik

Pernyataan itu echo e1, e2, ..., eN;dapat dipahami sebagai gula sintaksis untuk echo e1; echo e2; ...; echo eN;.

Karena semua ekspresi adalah pernyataan, dan echo eselalu memiliki efek samping yang sama dengan print e, dan nilai pengembalian print ediabaikan ketika digunakan sebagai pernyataan, kita dapat memahami echo esebagai gula sintaksis untuk print e.

Kedua pengamatan ini berarti yang echo e1, e2, ..., eN;dapat dilihat sebagai gula sintaksis untuk print e1; print e2; ... print eN;. (Namun, perhatikan perbedaan runtime non-semantik di bawah ini.)

Karena itu kita hanya perlu mendefinisikan semantik untuk print. print e, ketika dievaluasi:

  1. mengevaluasi argumen tunggal edan ketik-gips nilai yang dihasilkan ke string s. (Dengan demikian, print esetara dengan print (string) e.)
  2. Streaming string ske buffer output (yang akhirnya akan dialirkan ke output standar).
  3. Mengevaluasi ke integer 1.

Perbedaan pada level bytecode

print melibatkan overhead kecil untuk mengisi variabel return (pseudocode)

print 125;

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

echokompilasi tunggal ke satu opcode:

echo 125;

ECHO 125

echokompilasi multi-nilai ke beberapa opcodes

echo 123, 456;

ECHO 123
ECHO 456

Perhatikan bahwa multi-nilai echotidak menyatukan argumennya, tetapi mengeluarkannya satu per satu.

Referensi: zend_do_print, zend_do_echo.

Perbedaan runtime

ZEND_PRINT diimplementasikan sebagai berikut (pseudocode)

PRINT  var, result:

    result = 1
    ECHO var

Jadi pada dasarnya menempatkan 1variabel hasil dan mendelegasikan pekerjaan nyata ke ZEND_ECHOpawang. ZEND_ECHOmelakukan hal berikut

ECHO var:

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

di mana zend_print_variable()melakukan "pencetakan" yang sebenarnya (pada kenyataannya, itu hanya mengalihkan ke fungsi SAPI khusus).

Kecepatan: echo xvsprint x

Tidak seperti gema , hasil cetak mengalokasikan variabel sementara. Namun, jumlah waktu yang dihabiskan untuk kegiatan ini sangat kecil, sehingga perbedaan antara dua konstruksi bahasa ini dapat diabaikan.

Kecepatan: echo a,b,cvsecho a.b.c

Yang pertama dikompilasi menjadi tiga pernyataan terpisah. Yang kedua mengevaluasi seluruh ekspresi a.b.c., mencetak hasilnya dan langsung membuangnya. Karena penggabungan melibatkan alokasi memori dan penyalinan, opsi pertama akan lebih efisien.

Jadi yang mana yang harus digunakan?

Dalam aplikasi web, output sebagian besar terkonsentrasi di template. Karena templat digunakan <?=, yang merupakan alias echo, tampaknya logis untuk tetap echodi bagian lain dari kode juga. echomemiliki keuntungan tambahan karena mampu mencetak banyak ekspresi tanpa menggabungkannya dan tidak melibatkan overhead pengisian variabel pengembalian sementara. Jadi, gunakan echo.

pengguna187291
sumber
5
Saya telah mengedit dan mengklarifikasi hal ini secara ekstensif, dan menambahkan bagian tentang semantik. Saya cukup percaya diri tentang hal itu, tetapi seseorang dapat memeriksanya.
jameshfisher
1
Apakah ini berarti bahwa lebih baik digunakan echo $a,$b,$cuntuk penggabungan string vars? Jujur saya tidak pernah melihat ini digunakan.
geoff
1
Bagaimana dengan bagian TL; DR yang menjelaskan perbedaan fungsional? Seperti: printmemungkinkan hanya satu argumen, echomungkin ada banyak; echotidak dapat menjadi bagian dari ekspresi selagi printbisa dan kembali ...; dan mungkin beberapa ringkasan kinerja. Dan semua bagian "mengapa" dan "di bawah tenda" sesudahnya
YakovL
0

Saya tahu saya terlambat tetapi satu hal yang ingin saya tambahkan adalah bahwa dalam kode saya

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

memberikan kesalahan "kesalahan sintaksis, 'echo' yang tidak terduga (T_ECHO)"

sementara

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

bekerja dengan baik.

Documents tentang gema mengatakan "gema (tidak seperti beberapa konstruksi bahasa lain) tidak berperilaku seperti fungsi" di sini, tetapi tentang dokumen cetak juga mengatakan "cetak sebenarnya bukan fungsi nyata (ini adalah konstruksi bahasa)" di sini . Jadi saya tidak yakin kenapa. Dan juga tentang gema dan dokumen cetak mengatakan "Perbedaan utama untuk gema adalah bahwa cetak hanya menerima satu argumen dan selalu mengembalikan 1." sini

Saya akan senang jika ada yang bisa menjelaskan perilaku ini.

Mahad Ali
sumber