php单例数据库连接,这个代码是不好的做法吗?

Posted

技术标签:

【中文标题】php单例数据库连接,这个代码是不好的做法吗?【英文标题】:php singleton database connection, is this code bad practice? 【发布时间】:2012-03-02 21:35:48 【问题描述】:

我正在尝试创建一个简单的使用单例类来连接到 mysql 数据库并进行查询,代码工作正常,我没有遇到任何问题,但是由于我是 OOP 新手想知道这是否是不好的做法。

这是课程

class Database 
private $databaseName = 'dbname';
private $host = 'localhost';
private $user = 'user';
private $password = 'pass'; 
private static $instance; //store the single instance of the database

private function __construct()
    //This will load only once regardless of how many times the class is called
    $connection = mysql_connect($this->host, $this->user, $this->password) or die (mysql_error());
    $db = mysql_select_db($this->databaseName, $connection) or die(mysql_error()); 
    echo 'DB initiated<br>';


//this function makes sure there's only 1 instance of the Database class
public static function getInstance()
    if(!self::$instance)
        self::$instance = new Database();
    
    return self::$instance;     


public function connect()  
    //db connection
 
public function query($query) 
    //queries   
    $sql = mysql_query($query) or die(mysql_error()); 
    return $sql;


public function numrows($query) 
    //count number of rows  
    $sql = $this->query($query);
    return mysql_num_rows($sql);





//Intantiate the class
$database = Database::getInstance();

当我想使用该课程时,我会这样做:

$query = "SELECT * FROM registrations";
echo $database->numrows($query);
$sql = $database->query($query);

【问题讨论】:

单例模式通常在数据库类、记录器、前端控制器或请求和响应对象中实现。 我看不出有什么问题 您可以查看大量的 db 类。甚至查看诸如 codeigniter 之类的框架,看看它们的 db 类是如何工作的。 Who needs singletons? 的可能重复项 @diEcho 确实在***.com/a/4596323/208809 中进行了解释,并在其中给出了链接。你特别提到的那些可以很容易被butunclebob.com/ArticleS.UncleBob.SingletonVsJustCreateOne处理 【参考方案1】:

这种模式会很好,因为单例只适用于当前用户会话。决定实际上取决于您的优先事项。如果您想为用户提供更快的性能,那么您希望每个用户允许更多的数据库连接,但如果您想限制数据库受到攻击的程度,那么单例可以为您提供一个很好的中间路径。

【讨论】:

单身人士是个坏消息。应该避免它们。 @GordonM,非常正确。您的建议是更谨慎的长期解决方案。【参考方案2】:

我认为单例可以用于连接管理器,但不能用于连接本身。

您永远不知道何时需要为开发的特定部分建立额外的连接。假设您突然需要添加与远程数据库的同步。

连接管理器(可以管理多个连接)可以是单例的。连接本身;没有。

您的连接管理器还应该能够加载“驱动程序”,这样您就可以实例化 MySQL 连接,并且在您需要 msSQL、sqlite 或其他任何东西的那一天,您就可以添加所需的驱动程序。

【讨论】:

【参考方案3】:

单身人士是个坏消息。

他们将全局状态引入程序。大多数程序员应该熟悉为什么全局状态不好。 它们在单例和使用它的任何类之间引入了紧密耦合。这意味着您不能在不重用单例的情况下重用有问题的类。 他们使依赖于单例的类的单元测试成为问题,因为您不能轻易地用模拟替换单例。 他们鼓励类尝试解决自己的依赖关系的编码风格。这很糟糕,因为它会降低类所具有的依赖项的清晰度。 php 具有无共享架构,这意味着 PHP 单例根本不是真正的单例,任何时候都可以有多个活动实例(每个打开请求一个)。 如果您后来突然发现您实际上需要多个由单例提供的资源,会发生什么情况?这是一种比您想象的更常见的情况

您最好查看dependency-injection,因为它可以解决上述问题。

【讨论】:

您能否提供一些关于dependency-injection 的好文章以及为什么“数据库注册表”是个坏主意的解释? (我知道我可以用谷歌搜索它,但质量可靠且来源可靠) 注册中心在很多方面都类似于单例(全局状态、鼓励类解决依赖关系等)。至于 DI,如果你用谷歌搜索的话,那里有很多文章,就像你说的那样。 :) 我相信 Symfony 框架的文档包含了在 PHP 上下文中对 DI 的很好的讨论。 自动加载器类怎么样,(我的答案的扩展)get($connName) 将自动初始化与configs/$connName.ini 的连接?我知道您应该为“模型”提供来自“控制器”的连接,并且模型不应该像DBs::get('export') 那样做任何事情,但是指定默认连接有什么问题?【参考方案4】:

我听到的关于 PHP 中的 Singleton 设计模式的唯一积极论点是来自一位开发人员,他结合 Memcached 对象实现了 Singleton 数据库连接。我实际上并没有机会查看代码和性能,但他能够提出一个连贯的论点。

我个人不认为 Singleton 设计模式与 PHP 非常相关,无论如何它基本上是无状态的(正如在每个请求将有一个单例之前指出的那样)。

【讨论】:

以上是关于php单例数据库连接,这个代码是不好的做法吗?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用全局变量类(单例)是不好的做法? [复制]

在处理潜在的未定义变量时,在 PHP 中使用引用赋值是不好的做法吗?

让我的 Junit 测试与真实数据库交互是不好的做法吗?

Windows 服务中的计时器 .. 这个规模可以吗?会不会出现线程问题?这是不好的做法吗?

在数据库而不是假存储库上运行测试是不好的做法吗?

在微服务 REST api 调用中返回对象列表是不好的做法吗?