在PHP中使用OOP approch时,相关实例中数据库连接的更好方法是什么?
这是我的代码示例。
传递给构造函数的连接:
<?php
class Model {
public $db;
public function __construct($db) {
$this->db = $db;
}
}
在模型构造函数中连接到db。
class Model {
protected $db;
public function __construct() {
$this->db = new Detabase_Con();
}
}
用户模型
class Users extends Model {
public function showUsers() {
$this->db->select("SELECT * FROM users");
}
}
答案 0 :(得分:3)
这几乎是有争议的,但可以确保数据库连接不会被复制,并且更容易在现有代码中使用。
class DB {
private $instance=null;
private static function instance() {
if (self::$instance === null) {
self::$instance = new PDO(/*connection foo*/);
}
return self::$instance;
}
public static function __callStatic($method, $args) {
return call_user_func_array(array(self::instance(), $method), $args);
}
}
include('DB.php'); // the file containing the class
$sth = DB::prepare("SELECT foo");
$sth->execute();
$row = $sth->fetch();
这很大程度上来自于this回答中提出的简单PDO包装器。包装器是为了满足精确需求而编写的,因此请按原样使用。
这可能意味着你必须更好地思考你的代码,并且可能会重写它的大部分内容。关键是在类/函数签名中键入提示您的连接,以明确它取决于PDO:
class user{
function construct(PDO $db,$user_id) {
// define your user with the infos from $db
}
}
$db = new PDO(/*connection foo*/);
$wants_db = new user($db,$user_id);
如果您重写所有功能签名以通过$db
,您可能会发现它并不是更好,而且可能是真的。您可能必须重新设计应用程序的一部分,以便并非所有函数或方法都依赖于数据库连接。
单身方法现在更容易,可能适合您的需求,但会出现问题。如果您意识到将其作为参数传递是一种更好的方法,那么您不想启动它并重构代码
依赖注入兼容的方法现在更难,因为它意味着代码中的更改,但这种能量意味着您最终会更好/更清洁/更容易维护代码。
在尝试使用单例后,我认为实现注入数据库访问更好。我认为它代表了SOLID事物的一部分。我说这可以为php oop脚本中的数据库访问提供更好的未来验证方法。
答案 1 :(得分:-3)
让所有类继承自包含数据库连接的类是一个非常糟糕的主意。这不是MVC本身的问题,而是对面向对象编程方法的误用 因此,第一种方法看起来更好。
就个人而言,我喜欢将我的数据库连接作为单身人士。例如:
<?php
class MyDatabase extends PDO
{
public static function SharedInstance() {
static $instance = false;
if(!$instance) {
if(!($instance = new MyDatabase('mysql:.....', '', '', array(PDO::ATTR_PERSISTENT => true)))) {
throw new Exception('Cannot connect to database');
}
$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$instance->exec('SET NAMES utf8'); // MySQL only
}
return $instance;
}
// ... More methods and utils for the database class, if you need to extend it
}
?>
然后,代码中的任何地方(在任何范围内)我都可以通过以下方式回忆起与数据库的连接:
$db = MyDatabase::SharedInstance();
// And use it as a normal PDO object. For example:
$db->exec('some query');
您不需要使用PDO;您也可以使用MySQLi和其他数据库驱动程序。但是,当数据库驱动程序具有面向对象的接口时,它最有效。
PS:只是为了确保,始终使用准备好的陈述。上面对$db->exec
的调用只是暴露PDO界面的一个例子。
我知道单身人士有争议,我并不是说他们是解决任何问题的最佳方法。但是,在这种情况下,它们CAN和DO是有意义的。以下是我在评论中收到的一些批评:
他们使单元测试更难
由于我没有覆盖__construct()
方法以防止从MyDatabase
类初始化其他对象,因此您应该能够毫无问题地编写测试。
您正在对类名称进行硬编码
假设我们没有使用单身人士。许多用户会使用全局变量进行数据库连接,这仍然是“硬编码的东西”。无论如何,编程是硬编码的东西,所以我不明白为什么这应该是一个问题。最糟糕的情况:只需运行一个发现&amp;替换所有项目文件。任何编辑都可以轻松完成。
连接到多个(SQL)数据库更难
首先,我打赌只有0.01%的开发人员实际上需要连接到同一个PHP应用程序中的多个SQL数据库。对于那些做的人来说,单身人士可能是他们正在处理的最后一个问题
这么说,通过这种方法,您仍然可以连接到NoSQL数据库和缓存,实际上您可以在MyDatabase类中包含一些缓存逻辑。如果您需要使用PDO连接到另一个SQL数据库,那么只需创建PDO类的另一个实例(没有什么可以阻止您这样做!),或者创建另一个单例。同样,这不是问题。
您允许SQL注入
由于这只是PDO的一个包装,我想说PDO首先允许你进行SQL注入。如果您不知道如何使用预准备语句或正确引用您的查询参数,那么这不是我的错。
(您允许SQL注入)因为配置不当
我在上面的代码中没有看到任何配置。使用PDO只与数据库建立连接。
这很糟糕,因为这个SO帖子是这样说的
引自Wikipedia:
Ipse dixit,拉丁语为“他,他自己,说出来”,是一个术语,用于识别和描述一种任意的教条陈述,说话者希望听众接受这种陈述是有效的。 通过秃头地声称它是“它是怎么回事”来捍卫命题的谬论通过完全选择退出来扭曲论证:索赔人宣称问题是内在的,而不是可变的。
其他关于SO的帖子也会保护单身人士。然而,最后重要的是保持开放的心态,而不仅仅是在教条主义的背后绊倒自己。