(Ini lebih lama dari yang saya inginkan; mohon bersabarlah.)
Sebagian besar bahasa terdiri dari sesuatu yang disebut "sintaks": bahasa terdiri dari beberapa kata kunci yang ditentukan dengan baik, dan rangkaian lengkap ekspresi yang dapat Anda buat dalam bahasa tersebut dibangun dari sintaks tersebut.
Sebagai contoh, katakanlah Anda memiliki "bahasa" aritmatika empat fungsi sederhana yang hanya menggunakan bilangan bulat satu digit sebagai masukan dan sepenuhnya mengabaikan urutan operasi (saya katakan itu adalah bahasa sederhana). Bahasa itu dapat didefinisikan dengan sintaks:
// The | means "or" and the := represents definition
$expression := $number | $expression $operator $expression
$number := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
$operator := + | - | * | /
Dari ketiga aturan ini, Anda dapat membuat sejumlah ekspresi aritmatika dengan input satu digit. Anda kemudian dapat menulis parser untuk sintaks ini yang memecah setiap input yang valid ke dalam jenis komponen ( $expression
, $number
, atau $operator
) dan penawaran dengan hasilnya. Misalnya, ekspresi 3 + 4 * 5
dapat dipecah sebagai berikut:
// Parentheses used for ease of explanation; they have no true syntactical meaning
$expression = 3 + 4 * 5
= $expression $operator (4 * 5) // Expand into $exp $op $exp
= $number $operator $expression // Rewrite: $exp -> $num
= $number $operator $expression $operator $expression // Expand again
= $number $operator $number $operator $number // Rewrite again
Sekarang kami memiliki sintaks yang diurai sepenuhnya, dalam bahasa yang kami tentukan, untuk ekspresi asli. Setelah kita memiliki ini, kita dapat menelusuri dan menulis parser untuk menemukan hasil dari semua kombinasi $number $operator $number
, dan mengeluarkan hasil saat kita hanya memiliki satu yang $number
tersisa.
Perhatikan bahwa tidak ada $expression
konstruksi yang tersisa dalam versi parsing terakhir dari ekspresi asli kita. Itu karena $expression
selalu dapat direduksi menjadi kombinasi hal-hal lain dalam bahasa kita.
PHP kurang lebih sama: konstruksi bahasa diakui sebagai padanan dari kami $number
atau $operator
. Mereka tidak dapat direduksi menjadi konstruksi bahasa lain ; sebaliknya, mereka adalah unit dasar dari mana bahasa itu dibangun. Perbedaan utama antara fungsi dan konstruksi bahasa adalah ini: parser berhubungan langsung dengan konstruksi bahasa. Ini menyederhanakan fungsi menjadi konstruksi bahasa.
Alasan konstruksi bahasa mungkin atau mungkin tidak memerlukan tanda kurung dan alasan beberapa memiliki nilai kembalian sementara yang lain tidak bergantung sepenuhnya pada detail teknis spesifik dari implementasi parser PHP. Saya tidak begitu paham tentang cara kerja parser, jadi saya tidak bisa menjawab pertanyaan-pertanyaan ini secara spesifik, tapi bayangkan sejenak bahasa yang dimulai dengan ini:
$expression := ($expression) | ...
Secara efektif, bahasa ini bebas mengambil ekspresi apa pun yang ditemukannya dan menghilangkan tanda kurung di sekitarnya. PHP (dan di sini saya menggunakan tebakan murni) dapat menggunakan sesuatu yang serupa untuk konstruksi bahasanya: print("Hello")
mungkin dikurangi menjadi print "Hello"
sebelum diurai, atau sebaliknya (definisi bahasa dapat menambahkan tanda kurung dan juga menghilangkannya).
Inilah akar dari mengapa Anda tidak dapat mendefinisikan ulang konstruksi bahasa seperti echo
atau print
: mereka secara efektif dikodekan ke dalam parser, sedangkan fungsi dipetakan ke sekumpulan konstruksi bahasa dan parser memungkinkan Anda untuk mengubah pemetaan itu pada kompilasi- atau runtime ke gantilah kumpulan konstruksi atau ekspresi bahasa Anda sendiri.
Pada akhirnya, perbedaan internal antara konstruksi dan ekspresi adalah ini: konstruksi bahasa dipahami dan ditangani oleh parser. Fungsi bawaan, sementara disediakan oleh bahasa, dipetakan dan disederhanakan menjadi sekumpulan konstruksi bahasa sebelum parsing.
Info lebih lanjut:
- Bentuk Backus-Naur , sintaks yang digunakan untuk mendefinisikan bahasa formal (yacc menggunakan formulir ini)
Sunting: Membaca beberapa jawaban lain, orang membuat poin bagus. Diantara mereka:
- Bahasa bawaan lebih cepat untuk dipanggil daripada fungsi. Ini benar, jika hanya sedikit, karena interpreter PHP tidak perlu memetakan fungsi itu ke bahasa bawaannya yang setara sebelum parsing. Namun, pada mesin modern, perbedaannya bisa diabaikan.
- Sebuah bahasa bawaan melewati pemeriksaan kesalahan. Ini mungkin atau mungkin tidak benar, tergantung pada implementasi internal PHP untuk setiap builtin. Memang benar bahwa lebih sering daripada tidak, fungsi akan memiliki pemeriksaan kesalahan yang lebih canggih dan fungsionalitas lain yang tidak ada di dalamnya.
- Konstruksi bahasa tidak dapat digunakan sebagai callback fungsi. Ini benar, karena konstruk bukanlah fungsi . Mereka adalah entitas yang terpisah. Saat Anda membuat kode bawaan, Anda tidak mengkodekan fungsi yang membutuhkan argumen - sintaks dari bawaan ditangani langsung oleh parser, dan dikenali sebagai bawaan, bukan sebagai fungsi. (Ini mungkin lebih mudah dipahami jika Anda mempertimbangkan bahasa dengan fungsi kelas satu: efektif, Anda dapat meneruskan fungsi sebagai objek. Anda tidak dapat melakukannya dengan bawaan.)