2012-03-06 26 views
5

我正在使用PHP(但在這種情況下,我認爲編程語言並不重要),並且在我的班級方法中,我通常會遇到以下情況:標準化的返回值 - 這是好還是不好的想法

  1. 方法必須返回真正
  2. 方法必須返回真正錯誤消息
  3. 方法必須返回噸芸香 + 成功消息 + 錯誤消息
  4. 方法必須返回 + 成功結果(對象,數組等等)
  5. 方法必須返回true + 成功結果(object,array,whatever)false + 錯誤消息

我的問題是,當我用我的代碼這個類方法的地方,我總是要回來的類,並檢查什麼方法實際上返回:只需真正真正錯誤消息

是一個好主意,以規範的返回值?如果是,如何?

我的想法是:

  1. 如果函數返回真正然後簡單地返回
  2. 如果函數返回真正錯誤信息 then:

    if (success) 
    { 
        return array(
         TRUE, 
         null 
        ); 
    } 
    else 
    { 
        return array(
         FALSE, 
         $error_message 
        );  
    } 
    
  3. 如果函數返回真正 + 成功消息錯誤,那麼消息

    if (success) 
    { 
        return array(
         TRUE, 
         $success_message, 
        ); 
    } 
    else 
    { 
        return array(
         FALSE, 
         $error_message 
        );  
    } 
    

我希望你明白我的傢伙問題,甚至認爲我的解釋不是很好:) 您有哪些建議或最佳做法?我該如何處理?

UPDATE: 讓我們舉一個簡單的例子:

function login($username, $password) 
{ 
    // Login logic here .. 
    if ($logged_in) 
    { 
     return TRUE; 
    } 
    { 
     return $error_message; 
    } 
} 

那麼做,這將是正確的做法:返回,或拋出異常,並調用登錄方法時withing做一個嘗試捕獲。所以,當某個錯誤出現(驗證失敗等)時,我應該使用異常。

+1

這個問題不是很適合這個網站,可能會被關閉。請查看[常見問題](http://stackoverflow.com/faq)以獲取有關在此提出的問題的更多信息。 Stackoverflow並非真正意見或建議。 – jmort253 2012-03-06 08:26:13

+4

我正在尋找'最佳實踐',這在這種情況下非常有效。我需要一個'模式'使用..這是一個問題,我正在尋找一個解決方案。我不需要意見。我需要有效的解決方案。我認爲其他人也遇到類似的效率問題,而一個好的解決方案也可以幫助他們。 – 2012-03-06 08:28:27

回答

6

我想說返回布爾別的東西的前提是錯誤的。

函數應該有明確的目的和清晰的結果。如果可以實現此結果,則返回結果。如果結果無法實現,則函數返回false或引發異常。哪一個更好取決於情況和你的一般錯誤處理理念。無論哪種方式,使函數返回錯誤消息通常不會有用。該消息對調用該函數的代碼無用。

除了返回false結果:trigger_error之外,PHP還有其自己的機制來輸出錯誤消息。它純粹是一種幫助調試的工具,但它並不取代標準的返回值。它可以很好地適用於你想純粹爲了幫助開發者而顯示錯誤消息的情況。

如果一個函數足夠複雜,可能導致需要以不同方式處理的幾種不同類型的錯誤,則應該使用例外來實現。

例如,具有明確的目的性,僅需要返回一個很簡單的功能truefalse

function isUserLoggedIn() { 
    return $this->user == 'logged in'; 
} 

一個目的是可能不履行這一目的的功能:

function convertToFoo($bar) { 
    if (!is_int($bar)) { 
     return false; 
    } 
    // here be dragons 
    return $foo; 
} 

同樣的函數也會觸發一條消息,對調試很有用:

function convertToFoo($bar) { 
    if (!is_int($bar)) { 
     trigger_error('$bar must be an int', E_USER_WARNING); 
     return false; 
    } 
    // here be dragons 
    return $foo; 
} 

可以合法地碰上幾個不同類型的錯誤調用代碼需要知道一個函數:

function httpRequest($url) { 
    ... 

    if (/* could not connect */) { 
     throw new CouldNotConnectException('Response code: ' . $code); 
    } 

    ... 

    if (/* 404 */) { 
     throw new PageNotFoundException('Page not found for ' . $url); 
    } 

    return true; 
} 

我會在這裏粘貼此評論,以及:

It should not be the responsibility of the function to prepare, return or display an end-user error message. If the purpose of the function is to, say, fetch something from the database, then displaying error messages is none of its business. The code that called the fetch-from-database function merely needs to be informed of the result; from here there needs to be code whose sole job it is to display an error message in case the database function cannot get the required information. Don't mix those two responsibilities.

+0

我喜歡你在這裏給出的例子。我希望看到一個返回多個錯誤的例子,比如在驗證表單時,可能會有3或4個字段需要填寫,在這種情況下,異常不會有效? – bumperbox 2012-03-06 08:57:07

+0

如果驗證失敗,則可以拋出包含「字段」 - 「錯誤消息」對的異常。例如,如何在Kohana中使用ORM驗證。 – 2012-03-06 09:04:12

+1

@bumper這不是單一功能的責任。應該有一個(或幾個)函數試圖保存數據(或者你是否正在使用它),一些其他代碼設置錯誤消息,其中這些函數不成功,一些代碼將決定是否將該事件視爲整體是否成功,以及某些代碼是否顯示錯誤消息。把所有這些責任都歸結爲一個單一的功能,並希望它能「返回」一件事就是問題。 – deceze 2012-03-06 09:06:13

4

在特定情況下,您使用多個元素(不是相同類型實體的集合)返回數組的方法可能是可接受的解決方案。但總的來說,這是一種代碼味道。

一些問題,這樣的設計可以暗示:

  • 您沒有使用異常處理正常
  • 您的設計違背了單一職責原則
  • 你總是有回報,直到等待方法的結尾

如果一個方法真的不能做它應該做的事情,它不應該返回任何東西,它應該拋出一個異常。

如果你的方法不僅僅是一個任務,你必須重構。

儘早回來。寫入方法更像這樣:

if (!$something) 
{ 
    return FALSE; 
} 

//do some other stuff 
return 'great, it worked'; 

您的特定登錄函數不應該返回消息。這種特定於操作的用戶消息應該通過消息隊列進行解耦和處理。

所以你可以有一個注入你的控制器的Messenger類,這樣你就可以在任何地方使用它並將消息添加到隊列中。

function login($username, $password) 
{ 
    // Login logic here .. 
    if ($logged_in) 
    { 
     $this->messenger->addMessage('success', 'You are loggend in.'); 
     return TRUE; 
    } 
    { 
     $this->messenger->addMessage('error', $message); 
     return FALSE; 
    } 
} 
1

錯誤消息與返回值無關。 Antipatterns可能有助於避免已知的編碼錯誤。功能應根據名稱返回值是一致的宗旨,即:

canWriteFile() { return true or false } 
writeFile() { should return void } 

writeFile()程序員不期待任何價值,他必須學習文檔,成本的時候,不直觀,並可能導致錯誤。發明這樣的名稱,不需要任何文檔。

你絕對不應該使用與第一項布爾,第二項錯誤信息陣列 - 這個返回複雜的數據類型,而不是簡單的直觀的價值,你將常用功能寫入適配器和您的代碼很快結束變壞。

有3種可能性如何處理錯誤:

1)錯誤標誌/狀態用於通知

$error = ""; 
function foo() { 
    if($somethingBad) $error = "error occured"; 
    return !$somethingBad; 
} 

2)錯誤處理程序有用的大多數錯誤

function handleError($message) { 
    ... 
} 

function foo() { 
    if($somethingBad) handleError("error occured"); 
    return !$somethingBad; 
} 
有用

3)錯誤捕獲對於無法處理的錯誤很有用(即請求期間服務器脫機雲)

function foo() { 
    try { 
    // dangerous code here 
    } 
    catch($e) { 
    // handle error here 
    } 
    return !$somethingBad 
} 
+0

儘管可用性,我不會推薦1或2. ** 1 **,因爲全球狀態。 ** 2 **,因爲** 3 **更好。 – Dan 2013-05-01 14:57:26

+0

@Bracketworks:從人類的角度來看,是的。但** 3 **在大多數情況下要慢得多。 – 2013-05-01 19:07:03

+0

緩慢與否,我不認爲很多人會認爲這是一個明智的做法,可以幫助我們實現一個原生支持的語言結構。 – Dan 2013-05-01 19:43:56

1

嘗試例外

我建議潛入例外一點,因爲他們可以派上用場。首先,你擺脫了返回的錯誤信息:你拋出一個異常。其次,你不再需要真或假的返回代碼:如果所有東西都按預期工作,你就知道這是因爲沒有拋出任何異常。

如果您在類中處理成功和錯誤消息,您可能也想擺脫它們。這樣的事情應該在一個非常前端的類中處理,該類檢查異常,然後根據異常或成功消息設置錯誤消息。

可重用的類

方法應該返回對象的應用程序可以工作。當你開始使用返回值作爲通過系統傳遞的消息的時候,你將依賴於這些消息,因此很難替換底層的類。

一種好的思考方式如下:我可以在另一個項目中使用我的課程嗎?如果您有自定義錯誤消息,那麼可能很難,因爲您可能需要其他項目中的其他人並且必須更改您的課程。因此,您只想處理全局性成功或錯誤(通過例外),然後在您的前端附近添加自定義錯誤消息。

-2

這取決於你的應用正在做什麼。在一個案例中,我不得不設計一個基於REST API的大型應用程序,並且我希望錯誤能夠在API的任何部分冒出來並且是詳細的,直到用戶級別。所以我做的是:

  1. 每個函數都會返回一個錯誤/成功代碼,這應該是有意義的。
  2. OK是1,「General Failure」是0,所以它是布爾符合的。
  3. 專門的錯誤代碼值小於0.
  4. 你有一個枚舉所有值的類,所以你不必記住代碼。
  5. 此類還具有顯示和記錄錯誤的文本表示。
  6. 這個類也有2種方法OK($errorCode)FAIL($errorCode),裏面if小號

使用類看起來像

class Error { 

    const OK = 1; 
    //general error 
    const FAIL = 0; 
    //invalid url 
    const RequestParseError = -1; 
    //resource not found 
    const ResourceNotFound = -2; 

    .... 

    static public function _($errCode) { 

     switch ($errCode) { 

      case Error::OK: 
       return "OK"; 

      case Error::FAIL: 
       return "General Failure"; 

      case Error::RequestParseError: 
       return "Request Parse Error"; 

     ..... 
    } 

} 

這樣,應用程序的每個級別可以返回錯誤代碼,它會像你想要的那樣向上冒泡。並且OK()和FAIL()函數與布爾返回函數兼容。

+1

所以你正在複製PHP的異常處理? – markus 2012-03-06 09:05:55

+0

我討厭異常,我能說什麼。 – 2012-03-06 09:52:28

+0

讓我詳細說明一下:如果大多數情況下PHP的庫函數不會引發異常,那麼使用異常來執行此操作意味着將一個約定翻譯爲另一個約定,這很煩人。在Python中,凡是引發異常的東西都會更加簡單,並嵌入到語言哲學中。 – 2012-03-06 09:58:07

-1

A 標準方式顯然是這樣的:返回結果或者爲false。
錯誤拋出異常。

+0

返回混合值意味着在每次調用後測試類型:這是PHP的壞習慣,絕對不是標準。 – 2012-03-07 07:31:02

+0

是的,它不幸的是,這是在PHP中做事的標準方式;它是一致的(*時間*),所以這是值得的,但它有點臭。 – Dan 2013-03-25 22:40:00

3

來自其他語言的一種常見成語(,C#)是Do/TryDo方法配對。

/** 
* @param MyInput $input 
* @return MyOutput 
* @throws MyException 
*/ 
function myOperation(MyInput $input) 
{ 

} 

myOperation必須(在這種情況下MyException)表示操作的失敗拋出異常。成功時,返回結果值(MyOutput,在這種情況下爲)。

/** 
* @param MyInput $input 
* @param MyOutput $output 
* @return bool 
*/ 
function tryMyOperation(MyInput $input, &$output = null) 
{ 

} 

tryMyOperation必須返回指示失敗或操作的成功一個布爾值。它一定不能拋出異常(直接關係到操作成功或失敗)。該值被分配給通過引用傳遞的參數($output,在這種情況下爲)。通常,try*方法可以代理非try*方法。

一個人爲的例子:

/** 
* @param string $input 
* @return string 
* @throws TypeException 
*/ 
function stringToUpper($input) 
{ 
    if (!is_string($input)) 
    { 
     throw new TypeException('String expected'); 
    } 
    return strtoupper($input); 
} 

/** 
* @param string $input 
* @param string $output 
* @return boolean 
*/ 
function tryStringToUpper($input, &$output) 
{ 
    try 
    { 
     $output = stringToUpper($input); 
     return true; 
    } 
    catch (TypeException $exception) 
    { 
     $output = null; 
     return false; 
    } 
} 

而且將用作:

try 
{ 
    $output = stringToUpper($input); 
    // use $output 
} 
catch (TypeException $exception) 
{ 
    // recover 
} 

if (tryStringToUpper($input, &$output)) 
{ 
    // use $output 
} 
else 
{ 
    // recover 
} 

遵循這樣的慣例,語義和代碼的意圖更加清晰。如果要捕獲錯誤信息,請使用myOperation()catch錯誤信息。如果你不太在乎爲什麼東西壞了,而不是如果東西壞了,用tryMyOperation()

+0

+使用try {...} catch(...){...}的番茄' – 2013-03-25 22:46:28

+0

@crypticツ大聲笑,替代方案是?'嘗試{} ehh maybe_later;' – Dan 2013-03-25 22:49:20

+1

或更好,'嘗試{}錯過{/ *清理過道3 * /}' – Dan 2013-05-15 04:20:34

相關問題