2013-01-18 53 views
16

Trong PHP, bạn có thể xử lý các lỗi bằng cách gọi or die để thoát khi bạn gặp lỗi nhất định, như thế này:Trong PHP, tại sao "hoặc die()" hoạt động, nhưng "hoặc trả lại" thì không?

$handle = fopen($location, "r") or die("Couldn't get handle"); 

Sử dụng die() không phải là một cách tuyệt vời để xử lý các lỗi. Tôi muốn trả lại một mã lỗi để chức năng cha mẹ có thể quyết định phải làm gì, thay vì chỉ kết thúc kịch bản không đúng lúc và hiển thị lỗi cho người dùng.

Tuy nhiên, PHP hiển thị lỗi khi tôi cố gắng để thay thế or die với or return, như thế này:

$handle = fopen($location, "r") or return 0; 

Tại sao or die() làm việc, nhưng không or return 0?

Trả lời

21

Tôi muốn cảm ơn bạn đã đặt câu hỏi này, vì tôi không biết rằng bạn không thể thực hiện or return bằng PHP. Tôi đã rất ngạc nhiên khi bạn thử nghiệm nó. Câu hỏi này đã cho tôi một cái cớ tốt để làm một số nghiên cứu và chơi xung quanh trong nội bộ của PHP, mà thực sự khá thú vị. Tuy nhiên, tôi không phải là một chuyên gia về nội bộ của PHP, vì vậy sau đây là quan điểm của giáo dân về nội bộ PHP, mặc dù tôi nghĩ nó khá chính xác.


or return không hoạt động vì return không được coi là "hiện thân" của các phân tích cú pháp ngôn ngữ - đơn giản như vậy.

Từ khóa or được định nghĩa trong ngôn ngữ PHP như là một dấu hiệu gọi T_LOGICAL_OR, và sự biểu hiện duy nhất mà nó dường như được định nghĩa trông giống như this:

expr T_LOGICAL_OR { zend_do_boolean_or_begin(&$1, &$2 TSRMLS_CC); } expr { zend_do_boolean_or_end(&$$, &$1, &$4, &$2 TSRMLS_CC); } 

Đừng lo lắng về các bit trong niềng răng - điều đó chỉ xác định cách xử lý logic "hoặc" thực tế. Những gì bạn còn lại là expr T_LOGICAL_OR expr, mà chỉ nói rằng đó là một biểu thức hợp lệ để có một biểu thức, theo sau là mã thông báo T_LOGICAL_OR, tiếp theo là một biểu thức khác.

An expr cũng được định nghĩa bởi trình phân tích cú pháp, như bạn mong đợi. Nó có thể là r_variable, có nghĩa là đó là biến mà bạn được phép đọc hoặc expr_without_variable, là một cách ưa thích để nói rằng biểu thức có thể được tạo thành từ các biểu thức khác.

Bạn có thể làm or die() bởi vì ngôn ngữ xây dựng die (! Không phải là một chức năng) và bí danh của nó exit đều thể hiện bằng các dấu hiệu T_EXITT_EXIT được coi là một giá trị expr_without_variable, trong khi báo cáo kết quả return - thẻ T_RETURN - không phải là.

Bây giờ, tại sao T_EXIT được coi là một biểu thức nhưng T_RETURN thì không? Thành thật mà nói, tôi không có đầu mối. Có lẽ nó chỉ là một sự lựa chọn thiết kế được thực hiện chỉ để cho phép các cấu trúc or die() mà bạn đang yêu cầu. Thực tế là nó từng được sử dụng rộng rãi - ít nhất là trong những thứ như hướng dẫn, vì tôi không thể nói với một khối lượng lớn mã sản xuất - dường như ngụ ý rằng đây có thể là một sự lựa chọn có chủ ý. Bạn sẽ phải yêu cầu các nhà phát triển ngôn ngữ biết chắc chắn.


Với tất cả điều đó, điều này không quan trọng. Trong khi cấu trúc or die() dường như phổ biến trong các hướng dẫn (xem ở trên) một vài năm trước, nó không thực sự được đề nghị, vì nó là một ví dụ về "mã thông minh". or die() không phải là một cấu trúc của riêng nó, mà đúng hơn đó là một thủ thuật mà sử dụng - một số có thể nói lạm dụng - hai tác dụng phụ của các nhà điều hành or:

  • nó là rất thấp trong danh sách điều hành được ưu tiên, có nghĩa là thực tế mọi biểu thức khác sẽ được đánh giá trước khi là
  • là toán tử ngắn mạch, có nghĩa là toán hạng thứ hai (bit sau or) không được thực hiện nếu toán hạng đầu tiên trả về TRUE, vì nếu một toán hạng là TRUE trong biểu thức or, thì cả hai đều là.

Một số người coi loại thủ thuật này là không thuận lợi, vì người lập trình khó đọc hơn nhưng chỉ tiết kiệm được một vài ký tự không gian trong mã nguồn. Kể từ thời gian lập trình là tốn kém, và không gian đĩa là giá rẻ, bạn có thể thấy lý do tại sao mọi người không thích điều này.

Thay vào đó, bạn nên rõ ràng với ý định của bạn bằng cách mở rộng mã của bạn vào một if tuyên bố chính thức:

$handle = fopen($location, "r"); 
if ($handle) { 
    // process the file 
} else { 
    return 0; 
} 

Bạn thậm chí có thể làm nhiệm vụ biến ngay trong báo cáo kết quả if. Một số người vẫn tìm thấy điều này không thể đọc được, nhưng hầu hết mọi người (trong đó có tôi) không đồng ý:

if ($handle = fopen($location, "r")) { 
    // process the file 
} else { 
    return 0; 
} 

Một điều cuối cùng: đó là ước rằng trở 0 như một mã trạng thái chỉ ra thành công, vì vậy bạn có lẽ sẽ muốn quay trở lại một giá trị khác nhau để cho biết rằng bạn không thể mở tệp.

+0

Đó là điều thú vị về nó ... [Quay lại] (http://php.net/manual/en/function.return.php) là một ** ngôn ngữ xây dựng ** và không thể được sử dụng trong thời trang mong muốn của OP. Trong khi [die] (http://php.net/manual/en/function.die.php) cũng là một ** ngôn ngữ xây dựng ** nhưng vẫn có thể được sử dụng theo phương pháp mong muốn ở trên. Trong khi chết là một bí danh cho [exit] (http://php.net/manual/en/function.exit.php) một cấu trúc ngôn ngữ khác có thể được sử dụng. Trở lại là một trong những lẻ ra khỏi nhóm này. –

+0

@MarkTomlin Tôi không nghĩ rằng 'return' là cái lẻ ở đây. 'return' là một câu lệnh và được định nghĩa như vậy (cụ thể là' unticked_statement') cùng với các câu lệnh khác như 'if' và' foreach'. Nó rõ ràng phù hợp với nhóm đó. Tôi không chắc chắn tại sao 'exit' sẽ được coi là một biểu thức, vì việc gán nó cho một biến sẽ gọi hàm đó và giết kịch bản lệnh. Ngoài ra 'exit' là một hàm void, vì vậy bạn chỉ cần gán' NULL' cho biến, điều này không hữu ích. Tôi thực sự nghĩ rằng nó chỉ được coi là một biểu thức để cho phép 'hoặc die()' xây dựng để làm việc. Kỳ dị. – AgentConundrum

+1

+1 câu trả lời tuyệt vời, làm rõ một vài điều cho tôi :) – andr

0

Tôi cũng tình cờ gặp phải điều đó một lần. Tất cả tôi có thể tìm được điều này:

https://bugs.php.net/bug.php?id=40712

Nhìn vào comment xuống bên dưới:

đây không phải là một lỗi

Tôi đã tìm kiếm trong tài liệu và tôi nghĩ đó là do thực tế là return 0 là một tuyên bố trong khi die() về bản chất là một biểu thức. Bạn không thể chạy $handle = return 0; nhưng $handle = fun(); là mã hợp lệ.

Về xử lý lỗi, tôi sẽ giới thiệu mã tùy chỉnh hoặc sử dụng trình xử lý tùy chỉnh và trình kích hoạt. Ví dụ sau là described here.

0

Trả về khá đặc biệt - nó không thể giống như chức năng vì nó là công cụ để thoát khỏi các chức năng. Hãy tưởng tượng này:

if(1==1) return(); // say what?? 

Nếu nó là như thế này, trở sẽ phải là một chức năng mà không một "exit đôi", để lại không chỉ phạm vi riêng của mình nhưng người gọi, quá. Do đó sự trở lại không giống như một biểu thức, nó đơn giản là không thể làm việc theo cách đó.

Bây giờ trong lý thuyết, trả lại có thể là một biểu thức đánh giá (giả sử) sai và sau đó bỏ chức năng; có thể một phiên bản php sau này sẽ thực hiện điều này.

Điều tương tự cũng áp dụng cho goto sẽ là một nét duyên dáng để hoạt động như dự phòng; và có, những hạn chế là cần thiết và thường làm cho mã có thể đọc được, vì vậy nếu ai đó phàn nàn về "mã thông minh" (chắc chắn là điểm tốt) có lẽ php nên có một số cách "chính thức" để thực hiện một việc như vậy:

connectMyDB() fallback return false; 

Một cái gì đó như thử ... bắt, chỉ cần nhiều hơn đến điểm. Và cá nhân, tôi sẽ hạnh phúc hơn rất nhiều với "hoặc" làm công việc này vì nó hoạt động tốt với ngữ pháp tiếng Anh: "kết nối hoặc báo cáo thất bại".

TLDR: bạn hoàn toàn đúng: trả lại, goto, ngắt - không có công trình nào hoạt động. Dễ hiểu tại sao nhưng vẫn gây phiền nhiễu.

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