-1

我有一个名为 DB (class.pdo.php) 的类,它使用 PDO 和另一个名为 user 的类来处理我用来管理登录系统的 mysql 查询。

我的问题涉及始终必须在用户的每个公共函数中实例化 $db 以便我可以使用 DB。这有效率吗?我不应该在用户的 __construct() 中实例化数据库吗?

这是我的代码

 require_once("../../class.pdo.php");

class user {

private $db = null;

public function __construct(){
    /* Empty? */
}

public function find_by_email($email){
    $db = new db();
    $db->query('SELECT * FROM users WHERE email = :email LIMIT 1');
    $db->bind(':email',$email);
    $result = $db->single();
    return $result;
}

public function create($email,$password,$first_name,$last_name){ 
    $db = new db();
    $db->query("INSERT INTO users(email,password,first_name,last_name,created_at) VALUES (:email,:password,:first_name,:last_name,NOW())");
    $db->bind(':email',$email);
    $db->bind(':password',$password);
    $db->bind(':first_name',$first_name);
    $db->bind(':last_name',$last_name);
    $result = $db->execute();
    return $db->lastInsertId();
}

 [more similar functions ommited]
4

5 回答 5

3

好吧,尽管有一些评论建议使用单例模式,但我完全不同意将其用于此目的。

您的应用程序不会总是使用与一个数据库的单一连接。

让我告诉你我会怎么做:

class DbConnector {
    private $dbh;
    private $dsn;

    public function __construct($dsn) {
        $this->dsn = $dsn;
    }

    private function connect() {
        if($this->dbh === null) {
            $this->dbh = new PDO($this->dsn);
        }
    }

    public function disconnect {
        if($this->dbh !== null) {
            $this->dbh = null;
        }
    }

    public function query($sql) {
        $this->connect();
        //... do the rest
    }

    public function fetchAll($sql) {
        $this->connect();
        //... do the rest
    }

    public function insert($table, $values) {
        $this->connect();
        //... do the rest
    }

    public function update($table, $values, $cond) {
        $this->connect();
        //... do the rest
    }

    public function delete($table, $cond) {
        $this->connect();
        //... do the rest
    }
}

class User {
    private $dbConn;
    public function __construct(DbConnector $dbConn) {
        $this->dbConn = $dbConn;
    }

    public function create($email,$password,$first_name,$last_name){ 
        $this->dbConn->query("INSERT INTO users(email,password,first_name,last_name,created_at VALUES (:email,:password,:first_name,:last_name,NOW())");
        $this->dbConn->bind(':email',$email);
        $this->dbConn->bind(':password',$email);
        $this->dbConn->bind(':first_name',$email);
        $this->dbConn->bind(':last_name',$email);
        $this->dbConn->execute();
        return $this->dbConn->lastInsertId();
    }

    // ...
}

结果:

  • 没有使用单例 = 可测试。
  • 需要时才打开与数据库的连接
  • 您的连接是持久的。如果您在每种方法中打开和关闭连接,您将失去创建事务的能力。
于 2013-05-22T11:33:20.587 回答
2

如果使用 Singleton 模式为连接创建一个对象并在每次需要时使用它,而不是一直创建新对象呢?

于 2013-05-22T11:17:48.280 回答
1

我会用延迟加载做类似的事情:不要在构造函数中启动,除非你确定每次创建对象时确实需要连接,但绝对不要在每次方法调用时创建新对象。相反,将生成的对象保存到一个对象 var 中,该对象在每个方法调用上都会检查,如果丢失则启动连接。

class user {
  protected $_db = null;
  private function _init_db() { $this->_db = new XXX; }
  public function create( $x, $y, $z ) {
    if ( ! $this->_db ) $this->_init_db();
    # use $this->_db ..
  }
  public function find_by_email( $x, $y, $z ) {
    if ( ! $this->_db ) $this->_init_db();
    # etc
  }
}

这具有避免全局静态状态(单例..)的优点,并且仅在最后一刻创建连接/对象,因此您确定您确实需要它,而不仅仅是无用的连接。

于 2013-05-22T11:25:49.490 回答
1

说到效率,您的代码的主要问题是它为调用的每个方法都建立了新的连接。这确实是低效到杀死您的数据库服务器的地步。这与您遇到的其他问题无法比拟。

所以,一般来说,你可以有任何你想要的方式——要么在每个函数中以某种方式获取一个 db 类的实例,要么使用一个类变量——但无论哪种方式都必须在整个应用程序中使用单个 PDO 实例

此外,从代码量的角度来看,我发现您的函数效率很低,并且会以这种方式优化它们

public function create($email,$password,$first_name,$last_name){ 
    $sql = "INSERT INTO users(email,password,first_name,last_name,created_at) VALUES (?,?,?,?,NOW())";
    $this->db->query($sql);
    $result = $db->execute(func_get_args());
    return $db->lastInsertId();
}
于 2013-05-22T11:33:47.060 回答
0

从对象的角度来看,我会让数据库在方法中进行实例化,而不是在整个类中。

每个方法应该只看到它需要的变量和数据,以便执行它的功能。例如,一个createUser()方法需要查看变量或属性,例如$username, $usergroupId,$database等等。

但是,您可能有一个名为 的函数randomPassword(),它根据数字和字母生成随机密码。

这个 randomPassword() 函数不需要数据库对象,因此,在对象范围内已经初始化的数据库连接将是浪费的。

最好只在需要它的方法中创建新的数据库对象。

此外,在我的应用程序中,我不会在每次使用new database. 相反,我选择了保持连接处于活动状态的单例 PDO 数据库对象。

然后我可以静态调用数据库对象来检索现有连接。因此,如果在运行我的应用程序的过程中我需要有 20 个数据库对象,那么我的应用程序只返回相同的对象和相同的连接。

于 2013-05-22T11:15:11.063 回答