2013-10-12 117 views
0

在PHP MVC應用程序中處理可能的MySQL錯誤的最常見/最佳做法是什麼?將模型中的成功布爾值傳遞給控制器​​還是拋出異常最好? 可以說我正在調用一個存儲過程,我可能遇到的錯誤是db連接,用戶沒有權限,無效數據或隨機的MySQL錯誤,什麼可能是最有效/最有效的處理方法。PHP MVC MySQL錯誤處理

例如: 方法1:

//UserController.php 
private function get_user_info(){ 
    $user_info = $user_model->read_user_info(123); 

    if($user_info[0]){ 
     //Do stuff with user data 
    }else{ 
     //Check if db, permission, invalid data, or random MySQL error 
    } 
} 

//UserModel.php 
public function read_user_info($read_user_id){ 
    $stmt = $db->prepare("CALL read_user_info(?, ?)"); 

    $stmt->bindParam(1, $current_user_id); 
    $stmt->bindParam(2, $read_user_id); 

    if($stmt->execute()){ 
     $result_set = $stmt->fetchAll(PDO::FETCH_ASSOC); 

     //Does the user have permission to read other user's info 
     if($result_set["granted"]){ 
      return array(true, $result_set["user_info"]); 
     }else{ 
      return array(false, "Permission error"); 
     } 
    }else{ 
     return array(false, "MySQL error"); 
    } 
} 

方法2:

//UserController.php 
private function get_user_info(){ 
    try{ 
     $user_info = $user_model->read_user_info(123); 

     //Do stuff with user data 
    }catch(ConnectionException $e){ 

    }catch(InvalidDataException $e){ 

    }catch(MySQLException $e){ 

    } 
} 

//UserModel.php 
public function read_user_info($read_user_id){ 
    $stmt = $db->prepare("CALL read_user_info(?, ?)"); 

    $stmt->bindParam(1, $current_user_id); 
    $stmt->bindParam(2, $read_user_id); 

    if($stmt->execute()){ 
     $result_set = $stmt->fetchAll(PDO::FETCH_ASSOC); 

     //Does the user have permission to read other user's info 
     if($result_set["granted"]){ 
      return $result_set["user_info"]; 
     }else{ 
      throw new PermissionException(); 
     } 
    }else{ 
     throw new MySQLException(); 
    } 
} 
+0

從數據完整性違規的異常應在數據映射器(或其他形式的抽象存儲邏輯的)模型層內,當與域對象相互作用的手柄。數據完整性問題應該導致獲取與相應的域對象相關的錯誤狀態。連接/憑證例外可能在服務中。當從模型層查看請求數據(通過訪問作爲模型層的一部分的服務)時,將通知模型層中的錯誤狀態,並組合來自適當模板的響應。 –

+0

我不確定我100%是否遵循前兩句話,請問您可以重新填寫嗎?我現在想的是,存儲過程不需要擔心數據完整性,因爲它應該已經由模型內的驗證方法來處理。 –

+1

[This](http://stackoverflow.com/a/5864000/727208)可能會幫助您清除一些術語。對於「數據完整性檢查」,這將引發異常,我的意思是'UNIQUE'或'FOREIGN'關鍵違規。在其他RDBMS(如postgre和oracle)中,還可以在*列上添加'CONSTRAINTS',例如*「number必須在10到99之間」*。不要將它與作爲域邏輯一部分的驗證規則相混淆。該實例檢查您是否輸入了電子郵件,但不應該意識到甚至存在數據庫。 –

回答

1

難道是最好從模型到控制器或拋出異常傳遞的成功布爾?

整個錯誤處理將在模型中完成,因爲它是整個MVC應用程序概念中「可重用」代碼的適當位置。

什麼可能是最有效/最有效的處理方法。

我說這是方法1。首先,控制器只接收user_info變量,並在此事件上應用自定義邏輯,尤其不需要捕捉各種類型的Exception和處理(恕我直言,這應該集中在模型中)。

無論如何,設置自定義Error處理程序可能會變得非常有用 - 集中式方法,顯示錯誤,日誌管理等)。一個例子Error類我使用:

public static $error_types = array(
    E_ERROR => 'E_ERROR', 
    E_WARNING => 'E_WARNING', 
    E_PARSE => 'E_PARSE', 
    E_NOTICE => 'E_NOTICE', 
    E_CORE_ERROR => 'E_CORE_ERROR', 
    E_CORE_WARNING => 'E_CORE_WARNING', 
    E_COMPILE_ERROR => 'E_COMPILE_ERROR', 
    E_COMPILE_WARNING => 'E_COMPILE_WARNING', 
    E_USER_ERROR => 'E_USER_ERROR', 
    E_USER_WARNING => 'E_USER_WARNING', 
    E_USER_NOTICE => 'E_USER_NOTICE', 
    E_STRICT => 'E_STRICT', 
    E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', 
    E_DEPRECATED => 'E_DEPRECATED', 
    E_USER_DEPRECATED => 'E_USER_DEPRECATED' 
); 

public static $throwables = array(); 

public static function set_throwable_handlers() 
{ 
    error_reporting(E_ALL); 
    ini_set('display_errors', FALSE); 
    ini_set('log_errors', TRUE); 
    ini_set('error_log', APP_DIR.DIR_SEP.'system'.DIR_SEP.'logs'.DIR_SEP.'error.log'); 

    set_error_handler(array('Error', 'error_handler')); 
    set_exception_handler(array('Error', 'exception_handler')); 

    register_shutdown_function(array('Error', 'shutdown_handler')); 
} 

public static function set_throwable($error_number, $error_text, $error_file, $error_line) 
{ 
    self::$throwables[$error_number][] = array('type' => self::$error_types[$error_number], 'text' => $error_text, 'file' => $error_file, 'line' => $error_line); 
} 

public static function exception_handler(Exception $exception) 
{ 
    self::set_throwable($exception->getCode(), $exception->getMessage(), $exception->getFile(), $exception->getLine()); 
} 

public static function error_handler($error_number = '', $error_text = '', $error_file = '', $error_line = '') 
{ 
    self::set_throwable($error_number, $error_text, $error_file, $error_line); 
} 

public static function shutdown_handler() 
{ 
    $error = error_get_last(); 

    if ($error !== NULL) 
    { 
     self::set_throwable($error['type'], $error['message'], $error['file'], $error['line']); 

     View::display(); 
    } 
} 

public static function throw_error($error_text, $error_number = E_USER_NOTICE) 
{ 
    trigger_error($error_text, $error_number); 

    View::display(); 

    exit; 
}