Php 在另一个类中使用一个类时的OOP效率
我有一个名为DB(class.pdo.php)的类,它使用pdo对mysql查询进行所有处理,还有一个名为user的类,我用来管理登录系统 我的问题涉及到总是必须在用户的每个公共函数中实例化$db,这样我才能使用db。这有效吗?我不应该在用户的_construct()中实例化DB吗 这是我的密码Php 在另一个类中使用一个类时的OOP效率,php,class,oop,pdo,Php,Class,Oop,Pdo,我有一个名为DB(class.pdo.php)的类,它使用pdo对mysql查询进行所有处理,还有一个名为user的类,我用来管理登录系统 我的问题涉及到总是必须在用户的每个公共函数中实例化$db,这样我才能使用db。这有效吗?我不应该在用户的_construct()中实例化DB吗 这是我的密码 require_once("../../class.pdo.php"); class user { private $db = null; public function __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]
从对象的角度来看,我会让数据库在方法中实例化,而不是整个类 每个方法应该只看到它需要的变量和数据,以便执行它的功能。 例如,
createUser()
方法需要查看变量或属性,如$username
,$usergroupId
,以及$database
等
但是,您可能有一个名为randomPassword()
的函数,它根据数字和字母生成随机密码
此randomPassword()函数不需要数据库对象,因此,对象范围内已初始化的数据库连接将是浪费
最好只在需要的方法中创建新的数据库对象
此外,在我的应用程序中,我不会在每次使用新数据库时创建新数据库连接。相反,我选择了一个保持连接活动的单例PDO数据库对象
然后,我可以静态调用数据库对象来检索现有连接。因此,如果在运行应用程序的过程中需要20个数据库对象,那么应用程序只返回相同的对象和相同的连接 使用Singleton模式为连接创建一个对象,并在每次需要时使用它怎么样,不要总是创建新对象?我会对延迟加载做类似的事情:不要在构造函数中启动,除非您确定每次创建对象时都需要连接,但绝对不要在每次方法调用时创建新对象。相反,将生成的对象保存到一个对象变量中,该变量在每次方法调用时都会被检查,如果丢失,则会启动连接
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
}
}
这样做的好处是避免全局静态(Singleton…),并且只在最后一刻创建连接/对象,因此您可以确定您确实需要它,而且它不仅仅是一个无用的连接。尽管有一些评论建议使用Singleton模式,但我完全不同意将其用于此目的
您的应用程序并不总是只使用一个数据库连接
让我向您展示我是如何做到这一点的:
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();
}
// ...
}
结果:
- 未使用单例=可测试
- 需要时,只需打开与数据库的连接
- 您的连接是持久的。如果在每个方法中打开和关闭连接,则会失去创建事务的能力
说到效率,代码的主要问题是它为调用的每个方法建立了新的连接。这一个确实效率低下,甚至会杀死您的数据库服务器。这是你遇到的另一个问题所无法比拟的
因此,一般来说,您可以采用任何方式—在每个函数中以某种方式获取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();
}
你如何定义“有效”一词?如何衡量“效率”?实例化一次,然后使用依赖注入将其传递给所有需要它的类。您的类和PDO之间有什么区别?很可能效率低下。从软件工程的角度来看,这也不好:您的类(其方法)依赖于db
的存在,但不要在任何地方宣传这一点;只有当您阅读方法实现时,它才可见。@Afonso Gomes:服务器提供和使用了几十种不同的资源。而且您无法优化所有这些功能的使用。每次对资源A的优化都会消耗一些资源B。我不同意为每个方法创建一个连接,因为这样一来,数据库中的信息就不会持久化。连接器应在创建之前创建并传递给对象。每个方法都可以通过调用DB类中的connect
之类的方法来负责,因为创建DB对象时不需要立即连接。这就是所谓的惰性初始化。我同意@henriques Barcelos,我确实添加了一点,即我个人有一个单例PDO,我只是将它导入到每个需要它的方法中,而不是为每个方法创建一个新对象:)所以。。。你是说我在正确的轨道上?我在类dbSingleton的u构造中尝试了{$this->dbh=new PDO($dsn,$this->user,$this->pass,$options);}。如何使用单例对这些类进行单元测试?单例可能会导致单元测试出现问题,但是,在每次应用程序运行时打开10个连接,或者在适当的情况下打开1个可重用的连接,效率更高吗?为什么不合并父工厂模式以在正常请求时返回singleton对象,但在需要时返回新连接呢?singleton与其说是模式,不如说是反模式。数据库连接器不应使用singleton,因为并非总是只将一个连接连接到一个数据库。@HenriqueBarcelos是什么阻止您使用默认连接的singleton,但在提供不同凭据时创建另一个实例?如果不注入singleton,则无法更改它。如果只执行以下操作:public function someMethod(){DbConnector::getInstance()->query(…);}
您将永远无法更改连接器。@HenriqueBarcelos