2009-07-24 27 views
82

Tôi biết rằng include, isset, require, print, echo và một số khác không hoạt động nhưng là cấu trúc ngôn ngữ.Sự khác biệt giữa cấu trúc ngôn ngữ và chức năng "tích hợp sẵn" trong PHP là gì?

Một số cấu trúc ngôn ngữ này cần dấu ngoặc đơn, một số khác thì không.

require 'file.php'; 
isset($x); 

Một số có giá trị trả lại, một số khác thì không.

print 'foo'; //1 
echo 'foo'; //no return value 

Vì vậy, các nội sự khác biệt giữa một cấu trúc ngôn ngữ và một hàm built-in là gì?

Trả lời

123

(Đây dài hơn tôi dự định; xin vui lòng chịu với tôi.)

Hầu hết các ngôn ngữ được tạo thành từ một cái gì đó gọi là "cú pháp": ngôn ngữ bao gồm một số từ khóa được xác định rõ, và đầy đủ 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 số học đơn giản là "số" ngôn ngữ chỉ lấy số nguyên đơn là đầ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 theo 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ể tạo bất kỳ số biểu thức số học đầu vào đơn số. Sau đó bạn có thể viết một trình phân tích cú pháp cho cú pháp này phân tích bất kỳ đầu vào hợp lệ nào thành các loại thành phần của nó ($expression, $number hoặc $operator) và xử lý kết quả. Ví dụ, khái niệm 3 + 4 * 5 có thể được chia 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 đầy đủ phân tích cú pháp, trong ngôn ngữ định nghĩa của chúng tôi, đối với những biểu hiện ban đầu. Một khi chúng ta có điều này, chúng ta có thể đi qua và viết một trình phân tích cú pháp để tìm ra kết quả của tất cả các kết hợp của $number $operator $number và nhả ra một kết quả khi chúng ta chỉ còn lại một $number.

Lưu ý rằng không còn các cấu trúc $expression 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 giảm xuống thành một sự kết hợp của những thứ khác trong ngôn ngữ của chúng tôi.

PHP cũng giống nhau: cấu trúc ngôn ngữ được nhận dạng tương đương với $number hoặc $operator của chúng tôi. Chúng không thể giảm bớt vào 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 các hàm và cấu trúc ngôn ngữ là: trình phân tích cú pháp giao dịch trực tiếp với các cấu trúc ngôn ngữ. Nó đơn giản hóa các hàm thành các cấu trúc ngôn ngữ.

Lý do cấu trúc ngôn ngữ có thể hoặc không yêu cầu dấu ngoặc đơn và lý do một số có giá trị trả về trong khi một số khác không phụ thuộc hoàn toàn vào chi tiết kỹ thuật cụ thể của việc thực thi trình phân tích cú pháp PHP. Tôi không phải là thành thạo trong cách phân tích cú pháp hoạt động, vì vậy tôi không thể giải quyết những câu hỏi cụ thể, nhưng tưởng tượng trong một giây một ngôn ngữ mà bắt đầu với điều này:

$expression := ($expression) | ...

hiệu quả, ngôn ngữ này là miễn phí để lấy bất kỳ biểu thức nào nó tìm thấy và loại bỏ các dấu ngoặc đơn xung quanh.PHP (và ở đây tôi sử dụng phỏng đoán thuần túy) có thể sử dụng cấu trúc ngôn ngữ tương tự: print("Hello") có thể bị giảm xuống print "Hello" trước khi được phân tích cú pháp hoặc ngược lại (đị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à gốc của lý do bạn không thể xác định lại cấu trúc ngôn ngữ như echo hoặc print: chúng được mã hóa 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 bộ 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ạ đó tại thời gian biên dịch hoặc thời gian chạy để thay thế bộ 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 nội bộ giữa các cấu trúc và biểu thức là: cấu trúc ngôn ngữ được hiểu và xử lý bởi trình phân tích cú pháp. Các hàm dựng sẵn, được cung cấp bởi ngôn ngữ, được ánh xạ và đơn giản hóa thành một bộ cấu trúc ngôn ngữ trước khi phân tích cú pháp. Thông tin

thêm:

  • Backus-Naur form, cú pháp sử dụng để xác định ngôn ngữ chính thức (yacc sử dụng hình thức này)

Edit: Đọc qua một số các câu trả lời khác, người ta làm điểm tốt . Trong số đó:

  • Trình xây dựng ngôn ngữ được gọi nhanh hơn hàm. Điều này đúng, nếu chỉ có 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 hàm tương đương ngôn ngữ của nó trước khi phân tích cú pháp. Tuy nhiên, trên một máy móc hiện đại, sự khác biệt là khá không đáng kể.
  • Kiểm tra lỗi bỏ qua nội tuyến dựng sẵn ngôn ngữ. Điều này có thể hoặc có thể không đúng, tùy thuộc vào việc thực hiện nội bộ PHP cho mỗi nội trang dựng sẵn. Nó chắc chắn đúng là thường xuyên hơn không, chức năng sẽ có kiểm tra lỗi nâng cao hơn và các chức năng khác mà nội trang không có.
  • Không thể sử dụng cấu trúc ngôn ngữ làm hàm gọi lại. Điều này đúng bởi vì cấu trúc là không phải là hàm. Họ là những thực thể riêng biệt. Khi bạn mã một nội trang dựng sẵn, bạn không mã hóa một hàm nhận các đối số - cú pháp của nội trang dựng sẵn được xử lý trực tiếp bởi trình phân tích cú pháp và được nhận dạng dưới dạng hàm dựng sẵn, chứ không phải là hàm. (Điều này có thể dễ hiểu hơn nếu bạn xem xét các ngôn ngữ có chức năng hạng nhất: hiệu quả, bạn có thể truyền các chức năng xung quanh làm đối tượng. Bạn không thể làm điều đó với nội trang dựng sẵn.)
+3

wow! Cảm ơn câu trả lời tuyệt vời này! –

+2

Câu trả lời tuyệt vời là đủ mở để áp dụng cho nhiều ngôn ngữ, không chỉ PHP. Cảm ơn! –

+0

Chắc chắn rất dài, nhưng wow chắc chắn đáng giá. –

4

Sau khi lướt qua mã, tôi đã tìm thấy rằng php phân tích cú pháp một số câu lệnh trong tệp yacc. Vì vậy, họ là những trường hợp đặc biệt.

(xem Zend/zend_language_parser.y)

Bên cạnh đó tôi không nghĩ rằng có những khác biệt khác.

1

Bạn có thể override built-in functions. Từ khóa là mãi mãi.

+0

Đó không phải là chức năng tích hợp sẵn. Được định nghĩa trong phần mở rộng APD (Advanced PHP Debugger). –

+0

về chức năng ghi đè, bạn có thể có một loot tại phần mở rộng runkit (nó không phải là cốt lõi hoặc là, nó là một phần mở rộng, do đó, không trả lời cho OP, nhưng chỉ để trả lời này); nó thực sự mạnh mẽ, và gần đây hơn APD (và tôi tin rằng tôi đã nghe một số thời gian trước đây rằng một số người vẫn đang làm việc trên nó, ngay cả khi nó không được hiển thị trên pecl.php.net) –

14

Cấu trúc ngôn ngữ được cung cấp bởi chính ngôn ngữ đó (như các hướng dẫn như "if", "while", ...); do đó tên của họ.

Một hệ quả của điều đó là họ là nhanh hơn để được gọi hơn được xác định trước hoặc hàm do người dùng định nghĩa (hoặc vì vậy tôi đã nghe/đọc nhiều lần)

Tôi không có ý tưởng như thế nào nó được thực hiện, nhưng một điều họ có thể làm (vì được tích hợp trực tiếp vào langage) là "bỏ qua" một số loại cơ chế xử lý lỗi. Ví dụ, isset() có thể được sử dụng với các biến không tồn tại mà không gây ra bất kỳ thông báo, cảnh báo hoặc lỗi nào.

function test($param) {} 
if (test($a)) { 
    // Notice: Undefined variable: a 
} 

if (isset($b)) { 
    // No notice 
} 

* Lưu ý nó không phải là trường hợp cho các cấu trúc của tất cả ngôn ngữ.

Sự khác biệt giữa các hàm và cấu trúc ngôn ngữ là một số khác có thể được gọi mà không có dấu ngoặc đơn, như từ khóa.

Ví dụ:

echo 'test'; // language construct => OK 

function my_function($param) {} 
my_function 'test'; // function => Parse error: syntax error, unexpected T_CONSTANT_ENCAPSED_STRING 

Ở đây cũng vậy, nó không phải là trường hợp cho tất cả các cấu trúc ngôn ngữ.

Tôi cho rằng hoàn toàn không có cách nào để "vô hiệu hóa" ngôn ngữ xây dựng vì nó là một phần của chính ngôn ngữ đó. Mặt khác, nhiều chức năng PHP "tích hợp" không thực sự được tích hợp vì chúng được cung cấp bởi các phần mở rộng sao cho chúng luôn hoạt động (nhưng không phải tất cả)

Sự khác biệt khác là ngôn ngữ đó cấu trúc không thể được sử dụng như "con trỏ chức năng" (ý tôi là, callbacks, ví dụ):

$a = array(10, 20); 

function test($param) {echo $param . '<br />';} 
array_map('test', $a); // OK (function) 

array_map('echo', $a); // Warning: array_map() expects parameter 1 to be a valid callback, function 'echo' not found or invalid function name 

tôi không có bất kỳ ý tưởng khác đến tâm trí của tôi ngay bây giờ ... và tôi không biết nhiều về nội dung của PHP ...Vì vậy, đó sẽ có nó ngay bây giờ ^^

Nếu bạn không nhận được nhiều câu trả lời ở đây, có thể bạn có thể hỏi này đến mailing-list internals (xem http://www.php.net/mailing-lists.php), nơi có rất nhiều PHP lõi-phát triển ; họ là những người có lẽ sẽ biết về thứ mà ^^

(Và tôi thực sự quan tâm bởi những câu trả lời khác, btw ^^)

Là một tài liệu tham khảo: list of keywords and language constructs in PHP

+0

Bạn có thể có một hàm chấp nhận đặt biến mà không tạo thông báo bằng cách lấy biến theo tham chiếu. Điều này không giới hạn đối với các cấu trúc ngôn ngữ như isset(). –

+0

Ồ, đừng nghĩ về điều đó :-(Cảm ơn! –

Các vấn đề liên quan