我在这里看到的一个主要问题:
// This class requires some predefined globals
这可能会让你吃惊的,但我觉得你真正想要做的是,如果是这样的话,你不检查,当你定义了这个类,但是当你实例化它时。
当一个类实例化时,的构造函数被调用。这似乎是一个完美的地方给我检查的是:
class Product
{
public function __construct() {
// This class requires some predefined globals
$this->needGlobal('gLogger', 'db', 'glob');
}
private function needGlobal() {
foreach (func_get_args() as $global) {
if (!isset($GLOBALS[$global])) {
throw new RuntimeException(sprintf('Global %s needed but not set.', $global));
}
}
}
...
}
当你实例化一个Product
如果条件满足了它,然后会自动检查:
$blueShoes = new Product();
这不会,如果预工作条件不符合,但它会工作。
但这只是部分解决您的问题。您的代码的真正问题是Product
需要全局变量才能正常工作。
反而使产品只是把它需要与合作的事:
class Product
{
private $gLogger;
private $db;
private $glob;
public function __construct(LoggerInterface $gLogger, DbInterface $db, GlobInterface $glob) {
$this->gLogger = $gLogger;
$this->db = $db;
$this->glob = $glob;
}
...
}
用法:
$redShoes = new Product($gLogger, $db, $glob);
然后你不必计较什么内部Product
全球下去。
您已评论,希望逐步改进代码。你可以这样做,这是如何。正如上面写的第二个变体是要走的路,但是目前遗留代码与它不兼容。在任何情况下,如果Product
类是新代码,则应该使用依赖注入来编写它。将旧代码与新代码分开很重要。你不想让新代码吞噬遗留的东西。这会产生新的代码遗留代码,所以你将无法逐步改进。您只需添加新的旧代码。
因此,采用依赖注入的类定义。对于旧版的需求编写是屏蔽此第二类:
class ProductLegacy extends Product
{
public function __construct() {
// This class requires some predefined globals
list($gLogger, $db, $glob) = $this->needGlobal('gLogger', 'db', 'glob');
parent::__construct($gLogger, $db, $glob);
}
private function needGlobal() {
$variables = array();
foreach (func_get_args() as $global) {
if (!isset($GLOBALS[$global])) {
throw new RuntimeException(sprintf('Global %s needed but not set.', $global));
}
$variables[] = $GLOBALS[$global];
}
return $variables;
}
}
正如你所看到的,这个小存根汇集用新的方式做事情的方式全球。您可以在新代码中使用Product
类,并且如果您需要与旧代码进行接口,则可以使用类全局变量用于类实例化的类ProductLegacy
。
您也可以创建一个辅助函数来执行此操作,以便您可以将它用于不同的类。取决于你的需求。只需找到一个边框,您可以在旧代码和新代码之间绘制清晰的线条。
这个类是在那里声明的,所以它存在 – Esailija
顺便说一句,你可以使用'!isset($ gLogger,$ db,$ glob)'。 – deceze
@deceze,很棒的提示! – iMoses