2014-10-02 27 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

相关问题