2010-05-11 22 views
10

Tôi đang cố gắng để hiểu làm thế nào tôi nên thiết kế các lỗi xử lý các phần của mã của tôi. Gần đây tôi đã hỏi một câu hỏi tương tự về cách tôi nên đi về returning server error codes to the user, eg. 404 errors. Tôi đã học được rằng tôi nên xử lý lỗi từ bên trong phần hiện tại của ứng dụng; dường như đủ đơn giản.Tôi nên xử lý các lỗi dự kiến ​​như thế nào? ví dụ. "tên người dùng đã tồn tại"

Tuy nhiên, tôi nên làm gì khi không thể xử lý lỗi từ liên kết hiện tại trong chuỗi? Ví dụ, tôi có thể có một lớp được sử dụng để quản lý xác thực. Một trong những phương pháp của nó có thể là createUser($username, $password). Chỉnh sửa: Phương thức này sẽ trả lại id người dùng hoặc đối tượng người dùng. Trong hàm đó, tôi cần phải xác định xem tên người dùng đã tồn tại chưa. Nếu điều này là đúng, làm thế nào tôi nên cảnh báo mã gọi điện thoại về điều này? Trả về null thay vì một đối tượng người dùng là một cách. Nhưng làm cách nào để tôi biết được nguyên nhân gây ra lỗi?

Tôi nên xử lý lỗi như thế nào để mã gọi điện có thể dễ dàng tìm ra nguyên nhân gây ra lỗi? Có một mẫu thiết kế thường được sử dụng cho loại tình huống này không?

Chỉnh sửa: Tôi quên đề cập: Tôi đang sử dụng PHP.


quyết: Trong khi nhiều người cho rằng trường hợp ngoại lệ không nên được sử dụng trong tình huống này, tôi đã đi đến kết luận rằng đó là giải pháp tốt nhất.

Thứ nhất, không có thay thế đơn giản, thanh lịch nào cho ngoại lệ. (Tôi cho rằng điều đó là không thể nếu không có một hệ thống được xây dựng thành ngôn ngữ ... ngoại lệ đã được tích hợp sẵn.)

Thứ hai, để đáp ứng "ngoại lệ chỉ nên được sử dụng cho các tình huống đặc biệt, và đây không phải là một "Lập luận: "When I call getFoo(), I actually expect to get a Foo. If I don't get it, it's by definition an exceptional event." (thông qua, pkainulainen)

Trả lời

3

có một vài mô hình chung:

1.   ném một exception.

2.   Trả về NULL hoặc FALSE và đặt thông số tham chiếu đến lỗi. Ví dụ.

function createUser($user, $password, &$error) 
{ 
     //... 
     // You could use any type of object here. This is just a simple example. 
     if(uniqueKeyFailure) 
     { 
      $error = new UserAlreadyExists(); 
      return NULL; 
     } 
     //.. 
} 

Nó có thể được gọi như:

$userCreateError = NULL; 
$res = createUser($user, $pass, $userCreateError); 
if($res === NULL) 
{ 
    // do something with $userCreateError 
} 

3.   Return NULL hoặc FALSE và cung cấp một nhận được lỗi cuối cùng (ví dụ curl_error).

Tôi muốn giới thiệu 1 hoặc 2. Lý do chính khiến mọi người tránh ngoại lệ đối với các lỗi "không có ngoại lệ" như đầu vào của người dùng là hiệu suất. Có một số lượng thảo luận hợp lý về điều này, chẳng hạn như Performance of try-catch in php.

Tôi không khuyến nghị 3 vì nó không phải là reentrant.

+0

Bạn có thể mở rộng ý nghĩa của việc 'đặt đối tượng lỗi' không? Cảm ơn! –

+1

Trong số ba trường hợp này, ngoại lệ dường như được thiết kế riêng để xử lý các loại kịch bản được mô tả trong câu hỏi. Bạn có thể chọn và chọn cách xử lý từng sự kiện đặc biệt dựa trên lớp và thông báo của ngoại lệ. – AndreiM

+0

@tehblanx - Tôi nghĩ rằng tôi không đồng ý. 'CreateUser' sẽ trả về' true' thành công và 'false' nếu ngược lại. Lý tưởng nhất là tất cả điều này sẽ được xử lý trong một lớp và chính lớp đó có thể xử lý các vấn đề phát sinh từ một đăng ký không thành công. – thetaiko

0

Bạn có thể trả về số nguyên được xác định trong tệp tiêu đề chung với tên như DUPLICATE_USER hoặc INVALID_PASSWORD hoặc bất kỳ thứ gì phù hợp cho việc sử dụng của bạn. Sau đó, chức năng người gọi có thể dễ dàng kiểm tra các mã trả về này so với các khai báo tiêu đề toàn cục để xác định loại lỗi nào đã xảy ra.

+0

Tôi quên đề cập đến, phương thức này sẽ trả về thông tin (id người dùng hoặc đối tượng người dùng) nên tôi không thể trả về mã lỗi. –

+0

Tại sao không chỉ có phương thức trả về mã lỗi? – user97410

+0

Bởi vì khi người dùng đã được tạo, tôi muốn có thể theo dõi/sử dụng thông tin về người dùng mới. Nếu phương thức trả về một đối tượng người dùng thì tôi có thể tiếp tục. Nếu không, sau đó tôi sẽ phải chạy một truy vấn thứ hai để tìm người dùng bằng tên người dùng của họ. Trong khi đó là dễ dàng trong tình huống này bởi vì tên người dùng sẽ là duy nhất, có rất nhiều ví dụ mà tôi sẽ cần id để xác định thông tin, ví dụ như. lưu trữ nhật ký. –

0

này sẽ phải được thực hiện theo cách sau -

Tạo một đối tượng lỗi với mã lỗi trong đó, văn bản lỗi và phương pháp mà ném lỗi.

Vượt qua đối tượng lỗi.

Bạn có thể ném ngoại lệ trở lại nhưng trường hợp ngoại lệ là đắt

EDIT - Căn cứ vào chỉnh sửa của OP. Trong trường hợp đó, bạn sẽ phải ném một đối tượng ngoại lệ trở lại.

Tạo một lớp ngoại lệ với mã lỗi, mô tả lỗi, tên lớp, tên phương thức. Ném lại ngoại lệ.

-2

Bạn phải kiểm tra xem tên người dùng có tồn tại hay không TRƯỚC KHI gọi phương thức createUser(). Nếu bạn không, hoặc một cái gì đó xảy ra giữa thời gian bạn đã kiểm tra và gọi createUser(), bạn ném một ngoại lệ. Đó là hư không gần như đắt tiền như nó được thực hiện được.

Ứng dụng có tính phí không? Vâng. Nó có đủ lớn để quan trọng không? Có lẽ là không.

+1

Nó không phải là về chi phí, đó là về "một người dùng với tên đó đã tồn tại" không thực sự là một điều kiện đặc biệt. Nó thực sự dự đoán rằng điều này sẽ xảy ra. Ném một ngoại lệ là lạm dụng xử lý ngoại lệ. – timdev

+0

đó là vô nghĩa ngữ nghĩa! với loại lý do đó bạn có thể giải thích bất kỳ lỗi nào như "mong đợi" – hop

+0

Nếu bạn có thể dự đoán rằng nó có thể xảy ra, thì bạn kiểm tra trường hợp đó, trước khi cố gắng tạo người dùng, với isUserNameTaken() hoặc một cái gì đó. –

1

Tôi thường xử lý loại điều này bằng cách gắn xác thực của tôi bên trong một số đối tượng miền (như người dùng).

Ví dụ:

<?PHP 
$user->name = 'Joe'; 
$user->password = 'secret'; 

//try to save the user. 
if (! $user->save()){ 
    $errors = $user->getMessages(); 
    // ... do something with error messages 
}else{ 
    //the user object set it's own ID. 
    $id = $user->id; 
} 

Bây giờ, rất nhiều thứ là trừu tượng đằng sau người sử dụng. Có thể có cả vũ trụ vật thể trong đó, nhưng điều đó tùy thuộc vào bạn.

Vấn đề lớn hơn ở đây là: Tại sao trên thế giới bạn sẽ có lớp xác thực tạo người dùng? Việc tạo các đối tượng người dùng có thể nằm ngoài phạm vi của Xác thực.

Nó có thể là hợp lý để có một số phương pháp như authenticate($username,$password)trở một đối tượng kiểu 'sử dụng' (đại diện cho người sử dụng mà chỉ chứng thực), nhưng ngay cả đó là một chút lộn xộn.

Thay vì xem xét cái gì đó như:

<?PHP 
$auth = new AuthService(); 
$u = new User(); 
$u->username='Joe'; 
$u->password='secret'; 

$authResult = $auth->authenticate($user); 

if ($authResult->success){ 
    //$user has properties set as a side effect. 
}else{ 
    //find out why it failed. 
    $errors = $authResult->getErrors(); 
} 

Tất nhiên, điều này đòi hỏi bạn phải xác định một số loại lớp kết quả có giá trị cho AuthService :: authenticate() để cư trú và quay trở lại. Nhưng ít nhất bạn không kết thúc với các phương thức mà đôi khi trả về các phép toán và đôi khi trả về các đối tượng, v.v.

0

Nếu bạn kiểm soát kiểu trả về của phương thức, bạn cũng có thể thay đổi chữ ký của nó để trả về một thứ như đối tượng OperationResult sẽ có một thuộc tính ErrorDescription và thuộc tính UserID hoặc User object.

+0

Trả lại nhiều mục, có phần không liên quan, các mục từ một hàm có vẻ như một mùi mã. –

0

Cách dễ nhất: Trả về NULL nếu xác thực được thông qua và thông báo lỗi nếu không thành công. Ngăn chặn sự cần thiết phải thực hiện các lớp lỗi hoặc ngoại lệ. Cũng là tốt nhất cho hiệu suất.

ví dụ:

function numeric($input) { 
    if (!is_numeric($input)) return 'Must be numeric.'; 
    return NULL; 
} 

function usernameavailable($input) { 
    //query database.... 
    if ($result) return 'Username already taken, please choose another one.'; 
    return NULL; 
} 

Bạn có thể sử dụng chức năng với các thông số cũng như:

function length($input, $min, $max) { 
    if (strlen($input) < $min) return "Must be longer than $min characters."; 
    if (strlen($input) > $max) return "Must be shorter than $max characters."; 
    return NULL; 
} 

Members mỗi phần tử trong toàn bộ mẫu được thì cực kỳ dễ dàng. Chỉ cần lặp qua tất cả các phần tử, gọi tất cả các hàm xác thực cho phần tử đó và thu thập các chuỗi lỗi, nếu có. Nếu không có chuỗi lỗi, thì tất cả đầu vào của người dùng đều hợp lệ.

Tôi sẽ mạnh mẽ không khuyến khích các đề xuất được thực hiện bởi một trong các câu trả lời khác. Dữ liệu nhập người dùng không hợp lệ không phải là Đặc biệt và không yêu cầu ngoại lệ hoặc lỗi. Nó chỉ đơn giản là một trường hợp sử dụng dự kiến ​​mà phải được xử lý theo cách đơn giản nhất có thể.

Với phương pháp này, bạn có thể xây dựng một lớp Biểu mẫu khá dễ dàng và đơn giản là khởi tạo các phần tử với các đối số là các hàm xác thực. Bạn cũng có thể mở rộng điều này để bao gồm việc xác thực AJAX gửi các yêu cầu không đồng bộ tới các hàm xác nhận hợp lệ PHP chính xác.

Ví dụ từ khuôn khổ của tôi:

$Form = new AjaxForm(); 
$Form->add(new TextBox('Username', 'usernameavailable|length[3,12]')); 
$Form->add(new SubmitButton()); 

Chỉ với ba dòng tôi đã tạo ra một hình thức đầy đủ chức năng với cả hai phía khách hàng và xác nhận phía máy chủ. Tất nhiên tất cả các chi tiết đều tùy thuộc vào bạn nhưng tôi vẫn tin rằng đầu vào người dùng không hợp lệ nên được mong đợi và không phải là Đặc biệt.

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