Tôi có nên sử dụng khẳng định trong mã PHP của mình không?


87

Một đồng nghiệp đã thêm lệnh khẳng định một vài lần trong các thư viện của chúng tôi ở những nơi mà tôi đã sử dụng câu lệnh if và đưa ra một ngoại lệ. (Tôi thậm chí chưa bao giờ nghe nói về khẳng định trước đây.) Đây là một ví dụ về cách anh ấy sử dụng nó:

assert('isset($this->records); /* Records must be set before this is called. */');

Tôi sẽ làm:

if (!isset($this->records)) {
    throw new Exception('Records must be set before this is called');
}

Từ việc đọc các tài liệu PHP trên khẳng định , có vẻ như bạn nên đảm bảo khẳng định đang hoạt động và thêm một trình xử lý trước khi sử dụng khẳng định. Tôi không thể tìm thấy một nơi mà anh ấy đã làm điều này.

Vì vậy, câu hỏi của tôi là, sử dụng khẳng định có phải là một ý tưởng hay được đưa ra ở trên không và tôi có nên sử dụng nó thường xuyên hơn thay vì if và ngoại lệ không?

Một lưu ý khác, chúng tôi đang có kế hoạch sử dụng các thư viện này trên nhiều dự án và máy chủ, bao gồm cả các dự án mà chúng tôi thậm chí có thể không tham gia (các thư viện là mã nguồn mở). Điều này có tạo ra sự khác biệt nào trong việc sử dụng khẳng định không?


Nó có thực sự 'isset(dòng mã với assert) không? Không chỉ isset(không có trích dẫn duy nhất, ')?
Peter Mortensen

Câu trả lời:


79

Quy tắc ngón tay cái có thể áp dụng trên hầu hết các ngôn ngữ (tất cả những gì tôi mơ hồ biết) là một assertđược sử dụng để khẳng định rằng một điều kiện luôn đúng trong khi một điều kiện ifthích hợp nếu có thể hiểu rằng nó đôi khi sẽ thất bại.

Trong trường hợp này, tôi sẽ nói rằng assertlà thích hợp (dựa trên sự hiểu biết của tôi yếu của tình hình) vì recordsphải luôn luôn được thiết lập trước khi các phương pháp cụ thể được gọi là. Vì vậy, việc không thiết lập được bản ghi sẽ là một lỗi trong chương trình hơn là một điều kiện thời gian chạy. Ở đây, điều assertnày đang giúp đảm bảo (với thử nghiệm đầy đủ) rằng không có đường dẫn thực thi chương trình nào có thể khiến mã đang được bảo vệ với cái assertđược gọi mà recordschưa được đặt.

Ưu điểm của việc sử dụng assertnhư trái ngược với ifassertnói chung có thể được tắt trong mã sản xuất do đó làm giảm chi phí. Loại các tình huống được xử lý tốt nhất ifcó thể xảy ra trong thời gian chạy trong hệ thống sản xuất và do đó, không có gì bị mất nếu không thể tắt chúng.


4
Để thêm vào điều này, bạn có thể không muốn tắt các xác nhận trong mã sản xuất của mình, vì chúng giúp đảm bảo rằng các điều kiện "điều này sẽ không bao giờ xảy ra" vẫn như vậy. Có thể tốt hơn nếu để ứng dụng của bạn dừng xác nhận hơn là để người dùng của bạn tiếp tục đi theo một đường dẫn thực thi không nên tồn tại.
derekerdmann

2
@derekerdmann: Đúng. Đối với một số xác nhận, có thể đủ để ghi lại chúng (trong quá trình sản xuất) hoặc in cảnh báo (trong môi trường phát triển). Nhưng vì đôi khi các xác nhận cũng bảo vệ mã liên quan đến bảo mật, bạn cũng có thể bật assert_options(ASSERT_BAIL). Dù sao thì nó cũng nhanh hơn các cách giải quyết if / ném thủ công.
mario

4
@derekerdmann Tôi sẽ không đồng ý về điều này (trong bối cảnh sử dụng khẳng định () trong php). Đây là một lỗ hổng lớn, vì khẳng định () coi tất cả các đối số chuỗi là mã PHP, do đó (về mặt lý thuyết) có thể chèn và chạy mã tùy ý. IMHO, khẳng định nên được tắt về sản xuất
Vitaliy Lebedev

2
@VitaliyLebedev nếu bạn không muốn bị tiêm, đừng chuyển chuỗi để khẳng định.
Damon Snyder

9
Đến muộn nhưng PHP.net tuyên bố: "Các xác nhận chỉ nên được sử dụng như một tính năng gỡ lỗi."
Koen.

25

Hãy coi những lời khẳng định là "bình luận quyền lực". Thay vì một bình luận như:

// Note to developers: the parameter "a" should always be a number!!!

sử dụng:

assert('is_numeric(a) /* The parameter "a" should always be a number. */');

Ý nghĩa hoàn toàn giống nhau và dành cho cùng một đối tượng, nhưng nhận xét đầu tiên dễ bị quên hoặc bị bỏ qua (bất kể có bao nhiêu dấu chấm than), trong khi "bình luận quyền năng" không chỉ dành cho con người để đọc và hiểu, nó cũng liên tục được kiểm tra bằng máy trong quá trình phát triển và sẽ không bị bỏ qua nếu bạn thiết lập khả năng xử lý xác nhận tốt trong mã và trong thói quen làm việc.

Nhìn theo cách này, các xác nhận là một khái niệm hoàn toàn khác với if (error) ... và các ngoại lệ, và chúng có thể cùng tồn tại.

Có, bạn nên nhận xét mã của mình và vâng, bạn nên sử dụng "bình luận quyền lực" (khẳng định) bất cứ khi nào có thể.


Điều gì sẽ xảy ra nếu trong quá trình phát triển khi kiểm tra bạn luôn vượt qua điều kiện tốt cho xác nhận nhưng trong sản xuất nếu khẳng định bị tắt - một số người dùng vượt qua một điều kiện khác mà bạn không nghĩ đến khi kiểm tra? Hoặc nếu không, bạn cần phải khẳng định luôn bật, nhưng sau đó nó không giống như việc viết séc của riêng bạn?
Darius.V

Khi đó chương trình của bạn sẽ bị lỗi. Khắc phục sự cố đúng cách với câu lệnh if và các tính năng xử lý lỗi của ngôn ngữ và môi trường phát triển của bạn. khẳng định có thể phát hiện ra vấn đề, có nhiều cách khắc phục vấn đề tốt hơn.
DaveWalley

Lưu ý rằng kể từ PHP 7.2, việc chuyển một chuỗi vào xác nhận để đánh giá đã không còn được dùng nữa. Buồn, vì nó trông khá tiện dụng.
Jannie Theunissen

16

Nó hoàn toàn phụ thuộc vào chiến lược phát triển của bạn. Hầu hết các nhà phát triển không biết assert()và sử dụng thử nghiệm đơn vị hạ lưu. Nhưng các chương trình thử nghiệm tích hợp và chủ động đôi khi có thể có lợi.

khẳng định là hữu ích, vì nó có thể được bật và tắt. Nó không làm giảm hiệu suất nếu không có trình xử lý xác nhận như vậy được xác định. Bộ sưu tập của bạn không có mã này và bạn nên tạo ra một số mã tạm thời cho phép nó trong môi trường phát triển (nếu E_NOTICE / E_WARNINGs đang bật, nên là trình xử lý xác nhận). Đôi khi tôi sử dụng nó khi mã của tôi không thể chứa các loại biến hỗn hợp - tôi thường không tham gia vào việc nhập nghiêm ngặt trong một PHP được gõ yếu, nhưng có các trường hợp sử dụng ngẫu nhiên:

 function xyz($a, $b) {
     assert(is_string($a));
     assert(is_array($b));

Ví dụ, điều này sẽ bù đắp cho việc thiếu các chỉ định kiểu string $a, array $b. PHP5.4 sẽ hỗ trợ chúng, nhưng không kiểm tra.


"Php 5.4 sẽ có chúng nhưng không kiểm tra" nghĩa là gì?
Kzqai

1
PHP 5.4 có, hỗ trợ và kiểm tra các xác nhận.
DaveWalley

7

Assert không thay thế cho điều khiển luồng thông thường như ifhoặc ngoại lệ, bởi vì nó chỉ được sử dụng để gỡ lỗi trong quá trình phát triển.


6

Một lưu ý quan trọng liên quan đến khẳng định trong PHP sớm hơn 7. Không giống như các ngôn ngữ khác có cấu trúc khẳng định, PHP không ném ra hoàn toàn các câu lệnh khẳng định - nó coi nó như một hàm (thực hiện debug_backtrace () trong một hàm được gọi bởi một khẳng định). Tắt các xác nhận dường như chỉ làm cho chức năng không hoạt động gì trong động cơ. Lưu ý rằng PHP 7 có thể được thực hiện để mô phỏng hành vi này bằng cách đặt zend.assertions thành 0 thay vì các giá trị bình thường hơn là 1 (bật) hoặc -1 (tắt).

Vấn đề nảy sinh trong khẳng định đó sẽ nhận bất kỳ đối số nào - nhưng nếu đối số không phải là một chuỗi thì khẳng định nhận được kết quả của biểu thức cho dù khẳng định đang bật hay tắt. Bạn có thể xác minh điều này bằng khối mã sau.

<?php
  function foo($a) { 
    echo $a . "\n"; 
    return TRUE;
  }
  assert_options(ASSERT_ACTIVE, FALSE);

  assert( foo('You will see me.'));
  assert('foo(\'You will not see me.\')');

  assert_options(ASSERT_ACTIVE, TRUE);

  assert( foo('Now you will see'));
  assert('foo(\'both of us.\')');

Với mục đích khẳng định đây là một lỗi và một lỗi đã tồn tại từ lâu vì nó đã có trong ngôn ngữ này kể từ khi khẳng định được giới thiệu trở lại trong PHP 4.

Các chuỗi được truyền để khẳng định được đánh giá, với tất cả các tác động về hiệu suất và nguy cơ đi kèm với đó, nhưng đó là cách duy nhất để các câu lệnh khẳng định hoạt động theo cách mà chúng nên làm trong PHP (Hành vi này không được chấp nhận trong PHP 7.2).

CHỈNH SỬA: Đã thay đổi ở trên để lưu ý những thay đổi trong PHP 7 và 7.2


1
Trong PHP 7 có / sẽ có zend.assertionsthiết lập ini để tắt hoàn toàn assert().
Kontrollfreak

Đó là một tin tuyệt vời - nhưng dựa trên tài liệu ở đó, có vẻ như một bản vá cho PHPUnit là thứ tự, thêm một trình xử lý gọi lại khẳng định để ném AssertionException khi các xác nhận không thành công trong PHP 5.x. Bằng cách này, đơn vị kiểm tra có thể sử dụng chú thích @expectedException AssertionException bất kể họ chạy trên PHP 5.x hoặc 7.
Michael Morris

3

Assert chỉ nên được sử dụng trong phát triển vì nó hữu ích cho việc gỡ lỗi. Vì vậy, nếu bạn muốn, bạn có thể sử dụng chúng để phát triển trang web của mình, nhưng bạn nên sử dụng các ngoại lệ cho một trang web đang hoạt động.


7
Nhưng người ta vẫn sẽ có các xác nhận trong mã. Họ sẽ không hoạt động trong môi trường sản xuất.
aaronasterling

1
Thay vào đó, tôi sẽ giữ chúng trong quá trình sản xuất và điều chỉnh trình xử lý lỗi của mình cho phù hợp.
Daniel W.

3

Không, đồng nghiệp của bạn không nên sử dụng nó như một trình xử lý lỗi cho mục đích chung. Theo sách hướng dẫn:

Các xác nhận chỉ nên được sử dụng như một tính năng gỡ lỗi. Bạn có thể sử dụng chúng để kiểm tra sự tỉnh táo, kiểm tra các điều kiện luôn phải ĐÚNG và chỉ ra một số lỗi lập trình nếu không hoặc để kiểm tra sự hiện diện của một số tính năng nhất định như chức năng mở rộng hoặc các giới hạn và tính năng hệ thống nhất định.

Không nên sử dụng các xác nhận cho các hoạt động thời gian chạy bình thường như kiểm tra tham số đầu vào. Theo nguyên tắc chung, mã của bạn luôn có thể hoạt động chính xác nếu kiểm tra xác nhận không được kích hoạt.

Nếu bạn đã quen với các bộ kiểm thử tự động, động từ "khẳng định" thường được sử dụng để xác minh kết quả đầu ra của một số phương pháp hoặc hàm. Ví dụ:

function add($a, $b) {
    return $a + $b;
}

assert(add(2,2) == 5, 'Two and two is four, dummy!');
assert(is_numeric(add(2,2)), 'Output of this function to only return numeric values.');

Đồng nghiệp của bạn không nên sử dụng nó như một trình xử lý lỗi mục đích chung và trong trường hợp này là kiểm tra đầu vào. Có vẻ như trường bản ghi có thể không được một số người dùng trong thư viện của bạn đặt.


3

Đồng nghiệp của bạn thực sự đang cố gắng áp dụng thiết kế theo hợp đồng (DbC) từ ngôn ngữ Eiffel và dựa trên cuốn sách: Xây dựng phần mềm hướng đối tượng, Tái bản lần thứ 2.

Khi anh ta sử dụng khẳng định, sẽ là {P} -part của Hoare Logic hoặc Hoare Triple: {P} C {Q}, trong đó {P} là khẳng định điều kiện tiên quyết (ion) và {Q} là the post-condition khẳng định (ion) s.

Tôi sẽ lưu ý những lời khuyên quan trọng được đưa ra về tính năng khẳng định trong PHP có lỗi. Bạn không muốn sử dụng mã lỗi. Điều bạn thực sự muốn là các nhà sản xuất PHP sửa lỗi trong phần khẳng định. Cho đến khi họ làm như vậy, bạn có thể sử dụng khẳng định, nhưng hãy sử dụng nó có lưu ý đến trạng thái lỗi hiện tại của nó.

Hơn nữa, nếu tính năng khẳng định có lỗi, thì tôi khuyên bạn không nên sử dụng nó trong mã sản xuất. Tuy nhiên, tôi khuyên bạn nên sử dụng nó trong mã phát triển và thử nghiệm nếu thích hợp.

Cuối cùng - nếu bạn thực hiện một nghiên cứu về thiết kế theo hợp đồng, bạn sẽ thấy rằng có những hậu quả khi sử dụng các khẳng định Boolean dựa trên sự kế thừa cổ điển hướng đối tượng - nghĩa là - bạn không được làm suy yếu điều kiện trước, cũng như không được làm suy yếu điều kiện sau. Làm như vậy có thể gây nguy hiểm cho các đối tượng hậu duệ đa hình của bạn tương tác với nhau. Cho đến khi bạn hiểu điều đó nghĩa là gì - tôi sẽ để nó yên!

Hơn nữa - tôi thực sự khuyên các nhà sản xuất PHP nên nghiên cứu toàn diện về thiết kế theo hợp đồng và cố gắng đưa nó vào PHP càng sớm càng tốt! Sau đó, tất cả chúng ta đều có thể hưởng lợi từ việc có một trình biên dịch / thông dịch nhận biết DbC, sẽ xử lý các vấn đề được lưu ý trong các câu trả lời (ở trên):

  1. Một trình biên dịch nhận biết thiết kế theo hợp đồng được triển khai đúng cách (hy vọng) sẽ không có lỗi (không giống như khẳng định PHP hiện tại).
  2. Một trình biên dịch nhận biết thiết kế theo hợp đồng được triển khai đúng cách sẽ xử lý các sắc thái của quản lý logic xác nhận đa hình cho bạn thay vì khiến bạn phải suy nghĩ nhiều về vấn đề này!

LƯU Ý: Ngay cả việc bạn sử dụng if-statement để thay thế cho khẳng định (điều kiện trước) cũng sẽ phải chịu hậu quả nghiêm trọng nếu được sử dụng để củng cố điều kiện trước hoặc làm suy yếu điều kiện sau. Để hiểu điều đó có nghĩa là gì, bạn sẽ cần phải nghiên cứu thiết kế theo hợp đồng để biết! :-)

Chúc các bạn học và học vui vẻ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.