【问题标题】:PHP - How do I replace this Singleton? - Custom DBALPHP - 我如何替换这个单例? - 自定义 DBAL
【发布时间】:2012-07-05 04:50:15
【问题描述】:

我对设计模式的概念相当陌生,我正在考虑使用依赖注入和多态(因为每个都适用)——但是我有很多单例,虽然它们中的大多数可以很容易地更改,但我的 DBAL 不能.

DBAL 创建与数据库的连接的原因是——设置它自己的 PDO 对象。如果我将新的 DBAL 传递给每个需要它的类(相当多),我将获得多个不必要的数据库连接。

类是这样的

class DB {
    /**
     * Hold the PDO object
     * @var PDO
     */
    private $_db;

    /**
     * Hold the last error messages
     * @var string
     */
    private $_error_message = NULL;

    /**
     * Hold the last error code
     * @var int
     */
    private $_error_code = NULL;

    /**
     * Connects to the database server and selects a database
     *
     * @param string $user MySQL database user
     * @param string $password MySQL database password
     * @param string $name MySQL database name
     * @param string $host MySQL database host
     * @return bool
     */
    public function connect( $user, $password, $name, $host ) {
        // Connect
        try {
            $this->_db = new PDO( "mysql:host=$host;dbname=$name", $user, $password );
        } catch ( PDOException $e ) {
            $this->_error_message = $e->getMessage();
            $this->_error_code = $e->getCode();
            return false;
        }

        return true;
    }

    // ...
}
?>

会有很多类继承这个类——处理这个的最好方法是什么? (我是设计模式的新手)

【问题讨论】:

  • 工厂模式应该注意在实例化时将其注入对象中(单独实例化/从业务逻辑构建对象树,如果没有“内联”则经验法则@ 987654322@ 工厂除外)。
  • @Wrikken -- 这在理论上对我来说是有道理的,只是不完全确定我将如何去做,你能给我一个工厂方法的例子吗?工厂是静态调用的吗?还是工厂是单身?
  • 理想情况下,从测试的角度来看,您可能需要实例方法,但很难不陷入使所有内容都可以通过该实例访问的陷阱,从而使所有内容本质上都是全局的。我可以很好地忍受静态创建的“主要”对象,但在某种程度上,工厂(或特定的子工厂)本身也是您注入对象的东西。这很快就变得抽象了:P
  • @Wrikken -- 你有代码示例吗?对我来说有点太多了:)

标签: php design-patterns pdo singleton dbal


【解决方案1】:

另一种方法是使用注册表:

$db = new DB($host, $user, $pass);
Config::set('db', $db);

// Inside other classes
Config::get($this, 'db'); 
// Passes $this so the config can override the DB for different classes

这里的问题是你最终得到一个Config 单例。

要真正进行 DI,您基本上需要将对象传递给其他所有对象。

$db = new DB($host, $user, $pass);
$user = new User($db);
// Or with a DI container
$c = new Pimple();
$c['db'] = function() {
    return new DB($host, $user, $pass);
};

但是问问自己为什么不想使用单例。

如果它看起来像单例,闻起来像单例,并且您像使用单例一样使用它,那么单例模式可能最适合这项工作。

http://pimple.sensiolabs.org/

【讨论】:

    【解决方案2】:

    添加到班级:

    private function __construct($user, $password, $name, $host ){
      connect( $user, $password, $name, $host );
    }
    
    public static function getInstance(){
        if(self::$_db == NULL) self::$_db = new DB;
        return self::$_db;
    }
    

    并更改以下内容:

    // change $_db to be static!
    private static $_db = NULL;
    

    【讨论】:

    • 那将是一个单例,不是吗?我的意思是让它远离单身
    • 这不是我从你的问题中理解的。首先-您显示的代码不是单例,而不是添加我的代码。其次,您描述了您想要一个单例功能 - 那么为什么不使用单例呢?
    • 标题写着“替换这个单例”,我还指出类中有更多代码,我谈到了更改单例,但是在更改我的 DBAL 时遇到了麻烦。如果我想要一个单身人士,你的答案是完美的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-22
    • 2018-03-26
    • 2019-11-16
    • 2021-08-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多