在DB类的多个实例之间共享1个mysql连接

时间:2011-10-30 08:53:51

标签: php connection singleton mysqli reusability

我有点陷入以下问题:我希望我的所有课程都只使用1个单独的mysqli连接。我并不特别喜欢依赖注入(通过构造函数传递连接对我来说似乎不太优雅)所以我实现了一个单例。除了以下问题之外,这很有效:

class Admin {
  private $DB;

  public function __construct() {
    $this->DB = new DB::get_instance();
  }

  public function get_all_users() {
    $this->DB->query('SELECT `email` FROM `users`');
    while ($row = $this->DB->result->fetch_row()) { $users[] = new User($row[0]); }
    return $users;
  }
}

class User {
  private $DB;

  public function __construct($email = FALSE){
    $this->DB = new DB;
    if ($email) {
      $this->load($email);
    }
  }

  public function load($email){
    $this->DB->query('SELECT * FROM `users` WHERE email = "'.$this->email.'";'); // Problem!
    // etc.
}

这不能按预期工作(=只返回一个用户而不是所有用户),因为User中的query()用新的查询覆盖Admin的“mysqli_result var”(这显然是有意义的,因为只有DB的一个实例,因为它是一个单例)。因此,由于查询的嵌套,单例将无法工作。

我现在想要做的是将连接存储在一个单独的单例类中,并在移动中创建用于查询等的新数据库类(这将使用来自单例类的连接)。基本上是这样的:

class DB extendes Connection { .... } // Called as $DB = new DB in other classes
class Connection extends mysqli { .... } // This is a singleton

但我无法弄明白。如果我从DB调用parent :: __ construct(),它将创建一个新的Connection实例,这显然不是我正在寻找的。克隆连接显然也无法正常工作。如何告诉DB使用Connection中的mysqli链接而不实际创建新的Connection对象?

我希望我或多或少地清楚地解决了我的问题:)如上所述,我有些卡住了,到目前为止我没有找到任何有用的提示

2 个答案:

答案 0 :(得分:0)

等一下。 query()方法返回Result个对象。你为什么使用DB->result?无论你如何组织物体,你都会碰到同一面墙。

您应该迭代query()的结果,例如

public function get_all_users() {
  $result = $this->DB->query('SELECT `email` FROM `users`');
  while ($row = $result->fetch_row()) { $users[] = new User($row[0]); }
  return $users;
}

答案 1 :(得分:0)

<?php 
//Create a registry class to hold objects that traverse all the classes
Class Registry {
    private $vars = array();
    public function __set($index, $value){$this->vars[$index] = $value;}
    public function __get($index){return $this->vars[$index];}
}

//Your singleton db class
class db{
    private static $instance = NULL;
    private function __construct() {
    }
    public static function getInstance($DBHOST,$DBDB,$DBUSER,$DBPASS) {
        if (!self::$instance){
            self::$instance = new PDO("mysql:host=".$DBHOST.";dbname=".$DBDB, $DBUSER, $DBPASS);
            self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }
        return self::$instance;
    }
    private function __clone(){}
}


//assign the database object to the registry, within your initialization
$registry = new registry;
$registry->db = db::getInstance(DBHOST,DBDB,DBUSER,DBPASS);
$registry->router = new router($registry);
$registry->users = new users($registry);


//Then add to your class constructors to have that connection available
protected $registry;
function __construct($registry){
    $this->registry=$registry;
}

//.....
$result = $this->registry->db->query('SELECT ...')->fetchAll(PDO::FETCH_ASSOC);
foreach($result as $key=>$val){
    $this->registry->$val['setting']=$val['value'];
}

?>