(Điều này lâu hơn tôi dự định; hãy chịu đựng với tôi.)
Hầu hết các ngôn ngữ đều được tạo thành từ một thứ gọi là "cú pháp": ngôn ngữ này bao gồm một số từ khóa được xác định rõ ràng và phạm vi đầy đủ của các biểu thức mà bạn có thể xây dựng trong ngôn ngữ đó được xây dựng từ cú pháp đó.
Ví dụ: giả sử bạn có một "ngôn ngữ" số học bốn hàm đơn giản chỉ lấy các số nguyên có một chữ số làm đầu vào và hoàn toàn bỏ qua thứ tự các phép toán (tôi đã nói với bạn đó là một ngôn ngữ đơn giản). Ngôn ngữ đó có thể được xác định bằng cú pháp:
// The | means "or" and the := represents definition
$expression := $number | $expression $operator $expression
$number := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
$operator := + | - | * | /
Từ ba quy tắc này, bạn có thể xây dựng bất kỳ số lượng biểu thức số học đầu vào có một chữ số nào. Sau đó bạn có thể viết một phân tích cú pháp cho các cú pháp này mà phá vỡ xuống bất kỳ đầu vào hợp lệ vào loại thành phần của nó ( $expression
, $number
hoặc $operator
) và những giao dịch với kết quả. Ví dụ, biểu thức 3 + 4 * 5
có thể được chia nhỏ như sau:
// 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
Bây giờ chúng ta có một cú pháp được phân tích cú pháp đầy đủ, bằng ngôn ngữ xác định của chúng ta, cho biểu thức gốc. Khi chúng ta có điều này, chúng ta có thể xem qua và viết một trình phân tích cú pháp để tìm kết quả của tất cả các kết hợp của $number $operator $number
và đưa ra kết quả khi chúng ta chỉ $number
còn lại một kết hợp .
Lưu ý rằng không có $expression
cấu trúc nào còn lại trong phiên bản được phân tích cú pháp cuối cùng của biểu thức gốc của chúng tôi. Đó là bởi vì $expression
luôn có thể được rút gọn thành sự kết hợp của những thứ khác trong ngôn ngữ của chúng ta.
PHP cũng giống như vậy: các cấu trúc ngôn ngữ được công nhận là tương đương với $number
hoặc của chúng tôi $operator
. Chúng không thể được rút gọn thành các cấu trúc ngôn ngữ khác ; thay vào đó, chúng là các đơn vị cơ sở mà từ đó ngôn ngữ được xây dựng. Sự khác biệt chính giữa hàm và cấu trúc ngôn ngữ là: trình phân tích cú pháp xử lý trực tiếp với cấu trúc ngôn ngữ. Nó đơn giản hóa các chức năng thành các cấu trúc ngôn ngữ.
Lý do mà các cấu trúc ngôn ngữ có thể yêu cầu hoặc không cần dấu ngoặc đơn và lý do một số cấu trúc có giá trị trả về trong khi những cấu trúc khác không hoàn toàn phụ thuộc vào các chi tiết kỹ thuật cụ thể của việc triển khai trình phân tích cú pháp PHP. Tôi không rành về cách thức hoạt động của trình phân tích cú pháp, vì vậy tôi không thể giải quyết những câu hỏi này một cách cụ thể, nhưng hãy tưởng tượng trong giây phút một ngôn ngữ bắt đầu bằng điều này:
$expression := ($expression) | ...
Một cách hiệu quả, ngôn ngữ này có thể tự do sử dụng bất kỳ biểu thức nào mà nó tìm thấy và loại bỏ các dấu ngoặc đơn xung quanh. PHP (và ở đây tôi đang sử dụng phỏng đoán thuần túy) có thể sử dụng một cái gì đó tương tự cho các cấu trúc ngôn ngữ của nó: print("Hello")
có thể bị giảm xuống print "Hello"
trước khi nó được phân tích cú pháp hoặc ngược lại (các định nghĩa ngôn ngữ có thể thêm dấu ngoặc đơn cũng như loại bỏ chúng).
Đây là căn nguyên của lý do tại sao bạn không thể xác định lại các cấu trúc ngôn ngữ như echo
hoặc print
: chúng được mã hóa cứng một cách hiệu quả vào trình phân tích cú pháp, trong khi các hàm được ánh xạ tới một tập hợp các cấu trúc ngôn ngữ và trình phân tích cú pháp cho phép bạn thay đổi ánh xạ đó trong thời gian biên dịch- hoặc thời gian chạy thành thay thế tập hợp các cấu trúc hoặc biểu thức ngôn ngữ của riêng bạn.
Vào cuối ngày, sự khác biệt bên trong giữa cấu trúc và biểu thức là thế này: cấu trúc ngôn ngữ được trình phân tích cú pháp hiểu và xử lý. Các hàm tích hợp, mặc dù được cung cấp bởi ngôn ngữ, được ánh xạ và đơn giản hóa thành một tập hợp các cấu trúc ngôn ngữ trước khi phân tích cú pháp.
Thêm thông tin:
- Biểu mẫu Backus-Naur , cú pháp được sử dụng để xác định các ngôn ngữ chính thức (yacc sử dụng biểu mẫu này)
Edit: Đọc qua một số đáp án khác, mọi người cho điểm hay. Trong số đó:
- Nội trang ngôn ngữ gọi nhanh hơn một hàm. Điều này đúng, nếu chỉ là một chút, bởi vì trình thông dịch PHP không cần phải ánh xạ hàm đó tới các chức năng tương đương với ngôn ngữ nội trang của nó trước khi phân tích cú pháp. Tuy nhiên, trên một máy hiện đại, sự khác biệt là khá không đáng kể.
- Nội trang ngôn ngữ bỏ qua kiểm tra lỗi. Điều này có thể đúng hoặc không, tùy thuộc vào việc triển khai nội bộ PHP cho từng nội trang. Chắc chắn đúng là thường xuyên hơn không, các chức năng sẽ có tính năng kiểm tra lỗi nâng cao hơn và các chức năng khác mà các nội dung không có.
- Cấu trúc ngôn ngữ không thể được sử dụng làm hàm gọi lại. Điều này đúng, bởi vì một cấu trúc không phải là một hàm . Chúng là những thực thể riêng biệt. Khi bạn viết mã nội trang, bạn không mã hóa một hàm nhận đối số - cú pháp của nội trang được trình phân tích cú pháp xử lý trực tiếp và được công nhận là nội trang chứ không phải là một hàm. (Điều này có thể dễ hiểu hơn nếu bạn coi các ngôn ngữ có hàm hạng nhất: một cách hiệu quả, bạn có thể chuyển các hàm xung quanh dưới dạng đối tượng. Bạn không thể làm điều đó với nội trang.)