捕获异常时手动杀死应用程序?

时间:2014-10-02 12:52:04

标签: php oop exception

我有一个连接类,它在我__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)该应用程序?我认为这是例外。

2 个答案:

答案 0 :(得分: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()(不过是构造函数)。您可以使用工厂构建对象,并强制为您调用validate。做你喜欢的事!

在死亡的笔记中,不要死在申请表中。做你需要的让开发者调试(你)和用户(你或其他人)以不同的方式知道错误。通常,您将为开发人员登录并为用户提供消息。抓住异常并回答问题所在。

结束注释,这是一种方式。您可以使用Validation对象。您可以将validate()改为isValid(),然后返回true / false。您可以进行Connection对象调用validate() / isValid() - 这取决于您的体系结构以及您要执行的操作。关键是你已经将这两个类分开并同时使用了最佳实践。

最后的想法 - 确保你像我在我的代码中一样添加phpdoc。未来的开发者不想杀了你。我建议在你的代码中做一些愚蠢的事情时,检查出一个引发一些通知的IDE,比如phpstorm

答案 1 :(得分: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,作为旁注,你应该真正了解执行流程的工作原理。