2014-10-02 50 views
0

我有一個連接類,它初始化數據庫憑證時,我__construct它。捕獲異常時手動終止應用程序?

無論何時失敗,它都會拋出一個異常,即由於文件爲空或未設置變量而不能設置憑據。

變量現在不設置。

但我仍然可以調用該對象來調用該類中的其他函數,我不想要,因爲這是不可能的,沒有變量。就像這樣:

$connection = new Connection(); //Causes exception because variables arent set 
$connection->initialize(); //Should not be ran, because the variables arent set. Application shouldnt continue aswell. 
$connection->doFurtherThings(); //Wich shouldnt be run aswell, because the application couldnt go further without a db connection 

,這是什麼,而我之所以捕捉到的異常,並沒有讓值初始化?

public function __construct() { 
    try { 
     require "Configuration.php"; 
     $credentials = new Configuration('config.ini'); //Doesnt matter. just sets the configuration file 
     $credential = $credentials->getItems(); //Gets the items 

     if (isset($credential['engine'], $credential['host'], $credential['dbname'], $credential['username'], $credential['password'])) { 
      $this->engine = $credential['engine']; 
      $this->host  = filter_var($credential['host'], FILTER_VALIDATE_IP); 
      $this->dbname = $credential['dbname']; 
      $this->username = $credential['username']; 
      $this->password = $credential['password']; 
     } else { 
      throw new Exception("Login credential's arent not set"); 
     } 
    } catch (Exception $e) { 
     echo $e->getMessage(); 
    } 
} 

我是不是要die()應用自己的catch(Exception)裏面?我認爲這是一個例外。

+0

所以你不想要 - > getItems被調用,是否正確? – Luke 2014-10-02 12:58:16

+0

@Coulton不,我不希望應用程序可以進一步。當它不可能初始化數據庫變量時。包括我不能調用'$ connection-> initialize()' – Bas 2014-10-02 12:59:18

+0

它是實現者如何處理異常的決定,所以不要在構造函數中捕獲異常。 – 2014-10-02 12:59:21

回答

3

我明白你在做什麼。

您正在嘗試使用配置對象。這真棒,而且正是你應該做的。但是,你如何去做並不是最好的方法。

你甚至得到到使用該配置對象的代碼之前,您應該構建您的配置對象,並檢查對象是所有設置和有效嘗試使用另一個內的對象之前。消費對象的責任不在於驗證系統環境中的內部數據。您的Credentials對象。我們在這裏創造了一個接口,說:「任何憑據對象必須有一個validate()方法,並且該方法拋出一個異常,如果憑證無效。

interface Credentials 
{ 
    /** 
    * @throws CredentialsValidationException 
    */ 
    public function validate(); 
} 

爲什麼會出現一個validate()方法?因爲你不該將業務邏輯放置在對象的構造函數中。未來的開發人員知道他們可以調用validate()和會讓他們知道對象是否具有有效憑證。

現在到你的具體配置。在此Configuration對象,你就指出:「有一個有效的對象,用戶必須提供主機,數據庫名稱引擎,用戶名和密碼

class Configuration implements Credentials 
{ 
    protected $host; 
    protected $engine; 
    protected $dbName; 
    protected $username; 
    protected $password; 

    /** 
    * We're NOT validating here, we're just stating that this object requires 
    * these parameters to become an actual object 
    */ 
    public function __construct($host, $engine, $dbName, $username, $password) 
    { 
     $this->host  = $host; 
     $this->dbName = $dbName; 
     $this->engine = $engine; 
     $this->username = $username; 
     $this->password = $password; 
    } 

    /** 
    * As our Credentials interface requires, validate everything 
    * 
    * {@inheritDoc} 
    */ 
    public function validate() 
    { 
     // Check this is a valid object 
     // Consider using a Validation object passed in via Dependency Injection 
     // If it's not a valid object, throw a CredentialsValidationException 
    } 
} 

現在我們移動的責任。爲有效憑證到ConfigurationCredentials)對象本身的。下一步是實際使用這個對象。

class Connection 
{ 
    protected $credentials; 

    /** 
    * @param Credentials $credentials 
    */ 
    public function __construct(Credentials $credentials) 
    { 
     $this->credentials = $credentials; 
    } 
} 

在你Connection對象,你說明你需要實現Credentials接口的任何對象,所以您不僅在這裏獲得了使用polymorphism的能力,還將應用程序配置從您的類中解耦出來(您原本想做的事)。

您現在還在使用Dependency Injection;通過構造函數/方法傳遞對象以供消費類使用。這意味着你的代碼是分離的,你可以在應用程序的任何其他地方使用這些對象,或者如果你願意,可以在完全不同的庫中使用這些對象。

這裏是對象API,你現在可以使用:

$credentials = new Configuration('host', 'engine', 'dbname', 'user', 'pass'); 

try 
{ 
    $credentials->validate(); 

    $connection = new Connection($credentials); 

    // @todo Whatever else you want to do 
} 
catch (CredentialsValidationException $e) 
{ 
    // @todo Log the error here with a logger object (check out monolog) 
    // @todo Make sure the user viewing the code gets a nice response back 
} 

如果你想有效Connection對象,只需調用Configuration::validate()您正在使用它(而不是構造函數的方法,雖然)。您可以使用工廠來構建對象,並強制爲您調用驗證。你喜歡什麼!

在死亡的筆記中,不要死在應用程序中。做你需要讓開發者調試(你)和用戶(你或者其他人)以不同方式知道什麼是錯誤的。通常您會登錄開發人員併爲用戶發送消息。捕捉異常並回應問題是什麼。

結束說明,這是一個這樣做的方法。你可以使用一個Validation對象。您可以改爲validate()而不是isValid(),然後返回true/false。您可以使Connection對象調用validate()/isValid() - 這取決於您的體系結構以及您想要執行的操作。關鍵是你已經將這兩個類分離並同時使用了最佳實踐。

最後的想法 - 確保你像我在我的代碼中那樣添加phpdocs。未來的開發人員不會想要殺死你。並且我建議您在代碼中執行某些愚蠢的操作時查看一個IDE,該IDE會引發小小的通知,如phpstorm

+1

這太棒了。感謝您花時間解釋清楚。 – 2014-10-02 15:02:05

+0

@Jimbo首先,謝謝你的時間:)我一直在閱讀你的答案,它看起來非常好。唯一的一點就是它高於我的水平,我幾乎沒有OOP的經驗。所以我有幾個問題,驗證方法到底做了什麼?這是一個布爾值?在這種情況下,我在哪裏檢查數據庫在哪裏打開?我是否必須申報新物品,還是可以與現有的物品一起使用?如果我的英語不好,我很抱歉,我正在打電話給我。 – Bas 2014-10-02 17:08:27

+0

驗證方法是檢查字符串是否爲空,並且它們在給定的參數等範圍內(例如主機是具有'filter_var()'的IP地址)。例如,在做其他事情之前,你可以檢查數據庫在每個方法中的開放位置('$ this-> checkConnected();')。 – Jimbo 2014-10-03 10:35:48

2

就像我在評論中所說的那樣,應該調用者決定如何處理異常,而不是被調用的類。

在您的構造函數中,如果出現錯誤,應該拋出異常,並讓調用類決定如何處理該異常。

public function __construct() { 

    require "Configuration.php"; 
    $credentials = new Configuration('config.ini'); //Doesnt matter. just sets the configuration file 
    $credential = $credentials->getItems(); //Gets the items 

    if (isset($credential['engine'], $credential['host'], $credential['dbname'], $credential['username'], $credential['password'])) { 
     $this->engine = $credential['engine']; 
     $this->host  = filter_var($credential['host'], FILTER_VALIDATE_IP); 
     $this->dbname = $credential['dbname']; 
     $this->username = $credential['username']; 
     $this->password = $credential['password']; 
    } else { 
     throw new Exception("Login credential's arent not set"); 
    } 
} 

而現在它的調用者決定如何在出現異常的情況下做的,像停實例的執行:

try { 
    $connection = new Connection(); //Causes exception because variables arent set 
    $connection->initialize(); //Should not be ran, because the variables arent set. Application shouldnt continue aswell. 
    $connection->doFurtherThings(); 
} catch (Exception $e) { 
    exit($e->getMessage()); // Login credential's arent not set 
} 

爲了更好地說明這一點,我給你寫了一個simple example和一個側面說明,你應該真正瞭解執行流程如何工作。

+1

謝謝,但我真的不喜歡這個解決方案。初始化值是一個要求。 – Bas 2014-10-02 13:15:27

+1

@Bas你是什麼意思? – 2014-10-02 13:17:12

+0

初始化變量幾乎是必須的。如果它們不存在,則該頁面不應該繼續那麼做。因爲它不能加載它的數據 – Bas 2014-10-02 13:21:13

相關問題