【问题标题】:Pondering implementation: Instantiate class based on constant without reflection思考实现:基于不反射的常量实例化类
【发布时间】:2013-11-29 04:40:27
【问题描述】:

第二次更新

我认为我一直在从错误的一面来解决这个问题。假设我应该将“First”作为一个抽象类并只是在以后找到一种引用“Second”和“Third”的方法,我是否正确?

更新

根据一些反馈,我添加了一些内容来尝试澄清我想做的事情。类似于这种效果的东西。

我只看下面的代码就知道,“如果”它确实有效,并且因为它没有,我知道我是从错误的角度解决问题。最终目标不是根据我使用的一些框架的猜测,所有这些都是不常见的。

我更想将这段特定的代码基于 CodeIgniter 方法,您可以在其中定义(如下)是 STR_CLASS_NAME 在配置文件中,然后在任何时候通过程序的操作,像我一样使用它口授。

STR_CLASS_NAME = 'Second';

class First {
    protected $intTestOne = 100;

    public function __construct() {
         $strClassName = STR_CLASS_NAME;
         return new $strClassName();
    }

    public function TestOne() {
        echo $this->intTestOne;
    }

    protected function TestThreePart() {
        return '*Drum ';
    }
}

class Second extends First{
    /* Override value to know it's working */
    protected $intTestOne = 200;

    /* Overriding construct to avoid infinite loop */
    public function __construct() {}

    public function TestTwo() {
        echo 'Using method from extended class';
    }

    public function TestThree() {
        echo $this->TestThreePart().'roll*';
    }
}

$Test = new First();
$Test->TestOne(); <-- Should echo 200.
$Test->TestTwo(); <-- Should echo 'Using method from extended class'
$Test->TestThree(); <-- Should echo '*Drum roll*'

你可能会问,为什么要这样做而不是仅仅实例化 Second,嗯,有些情况会略有不同:

STR_CLASS_NAME = 'Third';

class Third extends First{
    /* Override value to know it's working */
    protected $intTestOne = 300;

    /* Overriding construct to avoid infinite loop */
    public function __construct() {}

    public function TestTwo() {
        echo 'Using method from extended class';
    }

    public function TestThree() {
        echo $this->TestThreePart().'snare*';
    }
}

$Test = new First();
$Test->TestOne(); <-- Should echo 300.
$Test->TestTwo(); <-- Should echo 'Using method from extended class'
$Test->TestThree(); <-- Should echo '*Drum snare*'

情况

我有一个抽象类,它用实际实现扩展了一个基类;在本例中是一个基本的 DB 包装器。

class DBConnector ()
class DBConnectorMySQLi extends DBConnector()

如您所见,MySQLi 是实现。现在,根据配置过程中的值,一个常量成为我希望使用的类名,在这种情况下(如下所示构建 DBConnectorMySQLi。

define('STR_DB_INTERFACE', 'MySQLi');
define('DB_CLASS', 'DBConnector'.STR_DB_INTERFACE);

目标

  • 拥有一个可以扩展以包含实现的基类
  • 对于代码本身不需要知道实现的名称实际上是什么
  • (在这种情况下)能够键入或使用项目接受的公共变量来创建 DBConnectorMySQLi。 IE。 $db 或类似的东西。 W

问题

在实际调用这个类时,我希望代码如下所示。我想知道这是否完全可能不需要添加任何额外的语法。附带说明一下,这个常数是 100% 保证被定义的。

$DBI = new DB_CLASS();

解决方案 1

我知道可以使用反射类(如 THIS QUESTION 中所讨论的那样),它通过以下方式工作:

$DBI = new ReflectionClass(DB_CLASS);

但是,这会创建比预期“更脏”的代码

解决方案 2

在DBConnector的构造函数中启动DBConnectorMySQLi的具体实现。

define('STR_DB_INTERFACE', 'MySQLi');
define('DB_CLASS', 'DBConnector'.STR_DB_INTERFACE);

class DBConnector() { public function __construct() { $this->objInterface = new DBConnectorMySQLi(); }
class DBConnectorMySQLi()

然而,这将导致需要继续将变量从一个“推”到另一个

任何建议都非常感谢

【问题讨论】:

  • 我最终要做的(而不是试图扭曲不想被扭曲的东西)是(根据给出的示例)“首先”一个抽象类,并且只有其他人扩展它。现在,这个练习的重点是,当涉及到操作时,可以很容易地为不同的接口编写一次代码,所以有一个基本的服务控制器 E.G.针对多个数据库或为不同的传输方法呈现内容,所有这些都使用相同的“内容库”。 DRY 原则和依赖注入仍然盛行。

标签: php class inheritance


【解决方案1】:

实例化类时可以使用变量。

$classname = DB_CLASS;
$DBI = new $classname();

来源:instantiate a class from a variable in PHP?

【讨论】:

  • 该方法(我在其他地方使用)需要额外的代码行。这让我想到了我会尝试的另一条消息
  • 试试$DBI = new ($classname = DB_CLASS)()。虽然它可能行不通。为什么你需要它在一条线上?
  • 我有一个需要重构的现有项目,我只是在思考究竟有哪些可用选项。正如标题中提到的,这是我在思考如何在创建最整洁的代码的同时实现它
  • 我完全赞成整洁的代码,但有时你只需要添加额外的一行。有时也有助于清晰。
  • 最整洁!== 最小。如果需要两行文字才能以清晰易懂的方式表达某事,那么您应该这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-18
  • 1970-01-01
  • 2020-07-10
相关资源
最近更新 更多