我有一个连接类,它在我__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 :(得分: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
}
}
现在,我们已将有效凭据的责任转移到Configuration
(Credentials
)对象本身。下一步是实际使用此对象。
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,作为旁注,你应该真正了解执行流程的工作原理。