2010-05-11 23 views
10

我很努力去理解我應該如何設計我的代碼的錯誤處理部分。我最近問了一個類似的問題,我應該怎麼去returning server error codes to the user, eg. 404 errors。我瞭解到,我應該在應用程序的當前部分內處理錯誤;看起來很簡單。我應該如何處理預期的錯誤?例如。 「用戶名已存在」

但是,我該怎麼辦時,我無法從鏈當前的鏈接處理錯誤?例如,我可能有一個用於管理身份驗證的類。其中一種方法可能是createUser($username, $password)編輯:此方法將返回用戶標識或用戶對象。在該函數中,我需要確定用戶名是否已經存在。如果這是真的,我應該如何提醒調用代碼呢?返回null而不是用戶對象是一種方法。但是,我怎麼知道是什麼導致了錯誤?

我應該如何在這樣一種方式,調用代碼可以很容易地找出導致錯誤處理錯誤?有這種情況下常用的設計模式嗎?

編輯:我忘了提及:我正在使用PHP。


解決:雖然很多人認爲,例外不應在這種情況下使用,我得出的結論是,這是最好的解決方案。首先,沒有簡單,優雅的例外替代方案。 (我認爲,如果沒有內置語言的系統,內置的系統是不可能的......異常已經內置。)

其次,對於「異常應該只用於例外情況,而且這不是「參數:"When I call getFoo(), I actually expect to get a Foo. If I don't get it, it's by definition an exceptional event."(經由pkainulainen

回答

3

有幾個共同的模式:

  1.拋出一個exception

  2.返回NULL或FALSE並設置在引用傳遞到一個錯誤。例如。

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; 
     } 
     //.. 
} 

它可以這樣調用:

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

3.  返回NULL或FALSE,並提供一個得到一個錯誤(例如curl_error)。

我會推薦1或2。主理人的避免「平常」錯誤異常,如用戶輸入的性能。對此有相當多的討論,如Performance of try-catch in php

我不建議3,因爲它是不可重入。

+0

請問您可以詳細說明「設置錯誤對象」的含義嗎?謝謝! – 2010-05-11 20:37:27

+1

在這三種情況下,異常似乎幾乎都是爲了處理問題中所描述的情況而設計的。您可以根據異常的類別和消息選擇如何處理每個例外事件。 – AndreiM 2010-05-11 20:41:55

+0

@tehblanx - 我想我不同意。 'createUser'應該在成功時返回'true',否則返回'false'。理想情況下,這將全部在班級中處理,班級本身可以處理由於註冊失敗而引起的問題。 – thetaiko 2010-05-11 21:33:36

0

您可以返回與名稱,如DUPLICATE_USER或INVALID_PASSWORD或任何適合您的使用全局頭文件中定義的整數。然後調用者函數可以根據全局頭聲明很容易地檢查這些返回碼,以確定發生了什麼樣的錯誤。

+0

我忘了提及,該方法將已經返回信息(用戶ID或用戶對象),所以我不能返回錯誤代碼。 – 2010-05-11 20:38:23

+0

爲什麼不只是讓方法返回錯誤代碼? – user97410 2010-05-11 20:43:45

+0

因爲一旦用戶被創建,我希望能夠跟蹤/使用有關新用戶的信息。如果該方法返回一個用戶對象,那麼我可以繼續前進。如果沒有,那麼我將不得不運行第二個查詢來通過用戶名找到用戶。雖然在這種情況下很容易,因爲用戶名將是唯一的,但有很多例子需要id來識別信息,例如。存儲日誌。 – 2010-05-11 20:49:05

0

這將在下面的方式來完成的 -

創建內部有錯誤代碼,錯誤文本和引發錯誤的方法的錯誤對象。

傳回錯誤對象。

你可以拋出異常回來,但

編輯例外是昂貴的 - 基於OP的編輯。在這種情況下,你將不得不拋出一個異常對象。

創建一個包含錯誤代碼,錯誤描述,類名稱,方法名稱的異常類。拋出異常。

-2

您需要在調用createUser()方法之前檢查用戶名是否存在。如果你沒有,或者在你檢查和調用createUser()之間發生了什麼,你會拋出一個異常。它的價格遠遠不及它的價格。

它是否有成本?是。它足夠重要嗎?很可能沒有。

+1

這不是關於費用,而是關於「具有該名稱的用戶已經存在」並非真正的特殊情況。實際上預計會發生這種情況。拋出異常是濫用異常處理。 – timdev 2010-05-11 20:53:43

+0

這是語義廢話!通過這種推理,您可以將任何錯誤解釋爲「期望」 – hop 2010-05-11 20:59:51

+0

如果您可以預見到它會發生,那麼在嘗試創建用戶之前,使用isUserNameTaken()或其他方法檢查該情況。 – 2010-05-11 21:02:30

1

我經常通過在一些域對象(如用戶)中粘貼我的驗證來處理這種事情。

例如:

<?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; 
} 

現在,很多東西是用戶的背後抽象。那裏可能有整個宇宙的物體,但這取決於你。

這裏面臨的一個更大的問題是:爲什麼在世界上你會有一個認證類創建用戶?用戶對象的創建可能超出了身份驗證的範圍。

authenticate($username,$password)返回類型爲'user'的對象(表示剛認證的用戶)可能是明智的,但即使這樣有點麻煩。

而是考慮是這樣的:

<?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(); 
} 

當然,這需要你定義AuthService某種結果值類::身份驗證()來填充和返回。但至少你不會結束有時返回布爾值的方法,有時返回對象等。

0

如果你控制方法的返回類型,你也可以改變它的簽名來返回類似於OperationResult對象的東西將具有ErrorDescription屬性和UserID或User對象屬性。

+0

從函數返回多個有點無關的項目聽起來像是一種代碼異味。 – 2010-05-11 21:51:08

0

最簡單的方法:如果驗證通過,則返回NULL,如果失敗則返回錯誤消息。防止需要製作錯誤類或例外。性能也是最好的。

例如。

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; 
} 

可以使用功能與參數,以及:

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; 
} 

在整個形式驗證的每個元素然後極爲容易。只需遍歷所有元素,調用該元素的所有驗證函數並收集錯誤字符串(如果有的話)。如果沒有錯誤字符串,則所有用戶輸入都是有效的。

我強烈勸阻其他答案之一提出的建議。無效的用戶輸入不是特例,不需要異常或錯誤。這只是一個預期的用例,必須以最簡單的方式處理。

使用此方法,您可以非常輕鬆地構建Form類,並簡單地實例化參數爲驗證函數的元素。您也可以擴展這個以包含AJAX驗證,將異步請求發送到完全相同的PHP驗證函數。從我的框架

例子:

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

只有三個我已經創建了兩個客戶端和服務器端驗證功能齊全的表格線。當然,所有的細節都取決於你,但我仍然相信無效的用戶輸入應該是預期的,而不是特例。

相關問題