2

我遇到了这段代码,它应该确保每个浏览器只创建一个数据库连接,以便应用程序看到由于对数据库的调用次数减少而提高的性能。

我相信我确实理解如何确保这一点的逻辑,但我只需要确认我对此的理解是正确和完整的。所以,请帮我解释细节。

在进行数据库连接/调用时还有比这更好的做法吗?

class Database {
    private static $dsn = 'mysql:host=localhost;dbname=mydatabase';
    private static $username = 'dbuser';
    private static $password = 'dbpass';
    private static $db;

    private function __construct() {}

    public static function getDB ()
    {
        if (!isset(self::$db)) {
            try {
                self::$db = new PDO(self::$dsn,
                                 self::$username,
                                 self::$password);
            } catch (PDOException $e) {
                $error_message = $e->getMessage();
                include('../errors/database_error.php');
                exit();
            }
        }
        return self::$db;
    }
}
4

1 回答 1

4

正如@raina77ow 在评论中指出的那样,这称为单例模式。这里有一些解释:

成为 Singleton 的重点是没有调用代码可以创建多个$db. 并提供从代码中任何地方对创建的$db.

静态类变量作为每个类的一个实例存在。$db因此,即使您可以将此类实例化为对象,也无法创建多个连接。

由于没有将类实例化为对象的目的(仅当类具有每个对象实例都存在的非静态变量时才有用),因此不需要类构造函数。为了防止调用代码被诱惑调用new,构造函数被设为私有。(严格来说,这样做并没有什么坏处,因为无论如何唯一的类变量都是静态的。)

请注意,您的实现缺少魔法__clone__wakeup方法。没有这些,你的 Singleton 仍然可以被克隆和反序列化。所以从技术上讲,你的 Singleton 没有正确执行奇异性。

以下是一些额外的想法:

  • 众所周知,单例类(或任何具有静态用法的类)难以集成到自动化测试中。由于它们是静态的,因此您可以将它们初始化一次,并且它们会在您的测试套件期间保持其状态。如果您使用非静态类,则可以在每次new用于实例化新对象时重新初始化它们。

  • 另一种设计是使用注册表模式,以及为您的应用程序创建一个非静态数据库实例并将其存储在注册表中的某种引导程序。

  • 如果您确实使用 Singleton,有时建议声明 Singleton 类final,以便没有子类可以覆盖行为或访问私有数据。

  • 您的数据库凭据在类定义中被硬编码为私有数据。我不会那样做的。如果您的 Apache PHP 处理程序配置错误,用户可以看到您的 PHP 源代码,然后他们将获得您的数据库密码。将数据库连接参数放入配置文件中,并将配置文件存储在 Apache 文档根目录之外。

  • 逐字输出数据库连接错误消息可以向用户透露信息。记录 PDO 错误消息,但向用户发出友好消息,例如“我们遇到问题,请通知站点管理员”。

  • 您不需要?>在类定义文件中终止 PHP 块。它增加了关闭后可能有空格或换行符的风险,这将成为应用程序中的空白并破坏布局。这些类型的错误令人抓狂。

于 2012-11-21T17:54:35.597 回答