在PHP中使用数据库访问单例的情况?

我通过PDO访问我的MySQL数据库。 我设置了对数据库的访问权限,我的第一个尝试是使用以下内容:

我想到的第一件事是global

$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'root', 'pwd');

function some_function() {
    global $db;
    $db->query('...');
}

这被认为是不好的做法。 经过一番搜索,我结束了Singleton模式,其中

“适用于需要单个课程实例的情况。”

根据手册中的例子,我们应该这样做:

class Database {
    private static $instance, $db;

    private function __construct(){}

    static function singleton() {
        if(!isset(self::$instance))
            self::$instance = new __CLASS__;

        return self:$instance;
    }

    function get() {
        if(!isset(self::$db))
            self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd')

        return self::$db;
    }
}

function some_function() {
    $db = Database::singleton();
    $db->get()->query('...');
}

some_function();

当我能做到这一点时,为什么我需要那个相对较大的班级?

class Database {
    private static $db;

    private function __construct(){}

    static function get() {
        if(!isset(self::$rand))
            self::$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'user', 'pwd');

        return self::$db;
    }
}

function some_function() {
    Database::get()->query('...');
}

some_function();

这最后一个完美的作品,我不必担心$db了。

我如何创建一个较小的单例类,或者是否有我在PHP中缺少的单例的用例?


好吧,当我刚开始职业生涯时,我一直在思考那个问题。 以不同的方式实现它,并提出了两个选择不使用静态类的理由,但它们非常大。

一个是,你会发现很多时候你绝对相信你永远不会有一个以上的实例,你最终会有第二个实例。 你可能会得到第二台显示器,第二台数据库,第二台服务器 - 无论如何。

当发生这种情况时,如果你使用了一个静态类,那么你的重构要比使用单例更糟糕。 单例本身就是一个不确定的模式,但它很容易转换为智能工厂模式 - 甚至可以转换为使用依赖注入而没有太多的麻烦。 例如,如果你的单例是通过getInstance()获得的,你可以很容易地将它改为getInstance(databaseName),并允许多个数据库 - 没有其他代码改变。

第二个问题是测试(老实说,这和第一个问题是一样的)。 有时候你想用模拟数据库替换你的数据库。 实际上,这是数据库对象的第二个实例。 与静态类相比,使用静态类要困难得多,你只需要模拟getInstance()方法,而不是静态类中的每一个方法(在某些语言中可能非常困难)。

这真的归结为习惯 - 当人们说“全球通”是不好的时候,他们有很好的理由这么说,但是直到你自己解决问题才会显而易见。

你能做的最好的事情就是问(像你一样),然后做出选择并观察决定的后果。 掌握解释你的代码随着时间的变化的知识要比首先做正确的事情重要得多。


单身人士甚少 - 如果不是说不 - 在PHP中使用。

在共享内存中存在对象的语言中,可以使用单例来保持内存使用率较低。 您不必创建两个对象,而是从全局共享的应用程序内存中引用现有实例。 在PHP中没有这样的应用程序内存。 在一个请求中创建的单例生活正是为了这个请求。 在另一个同时完成的请求中创建的单例仍然是完全不同的实例。 因此,Singleton的两个主要目的之一在这里不适用。

另外,在应用程序中概念上只存在一次的许多对象并不一定需要语言机制来执行此操作。 如果你只需要一个实例,那么不要实例化另一个实例。 只有当你没有其他实例时,例如当你创建第二个实例时小猫死亡,你可能拥有一个有效的Singleton用例。

另一个目的是在同一个请求中拥有一个全局访问点。 虽然这听起来可取,但它确实没有,因为它创建了与全局范围的耦合(如任何全局变量和静态变量)。 这使得单元测试变得更加困难,而且您的应用程序通常不易维护。 有一些方法可以缓解这种情况,但通常情况下,如果您需要在许多类中使用相同的实例,请使用依赖注入。

在PHP中查看我单张幻灯片的幻灯片 - 为什么它们不好,以及如何从应用程序中删除它们以获取更多信息。

即使是单身模式的发明人之一Erich Gamma,现在也怀疑这种模式:

“我赞成丢弃Singleton,它的使用几乎总是一种设计气味”

进一步阅读

  • 如何在PHP中测试注册表模式或单例模式?
  • 使用PHP数据库类作为单例的缺点是什么?
  • 使用PHP PDO的数据库抽象类设计
  • 单身人士会成为微博客网站的优秀设计模式吗?
  • 修改一个类来封装而不是继承
  • 如何访问另一个类的对象?
  • 为什么Singletons在PHP中没有用处
  • 清洁代码会谈 - 单身人士和全球国家
  • 如果在上述之后,你仍然需要帮助决定:


    谁需要PHP中的单身人士?

    注意几乎所有对单身人士的反对意见都来自技术立场 - 但他们的范围也非常有限。 特别是对于PHP。 首先,我将列举使用单身人士的一些原因,然后我将分析对单身人士使用的反对意见。 首先,需要他们的人:

    - 编写大型框架/代码库的人员将被用于许多不同的环境,他们必须使用以前存在的,不同的框架/代码库,并且必须实施来自客户/老板的许多不同的,不断变化的甚至是异想天开的请求/管理/单位领导做。

    看,单身模式是自我包容的。 完成后,单个类在所有包含它的代码中都是刚性的,它的行为与您如何创建其方法和变量完全相同。 它在给定的请求中始终是同一个对象。 由于无法将两次创建为两个不同的对象,因此即使将单例插入到两个,三个不同的,旧的,甚至意大利面条代码库中,也可以知道单个对象在代码中的任何给定位置。 因此,就开发目的而言,它更容易实现 - 即使在该项目中有许多人工作,当您看到单个代码在任何给定代码库中的某个点上初始化时,您都知道它是什么,它是干什么的,它是如何实现的它和它所处的状态。如果它是传统类,则需要跟踪该对象首先创建的位置,在该位置调用哪些方法直到该代码中的点及其特定状态。 但是,在那里放置一个单例,如果你在编写代码时丢弃了适当的调试和信息方法并追踪到单例,那么你确切知道它是什么。 因此,它使得那些必须使用不同代码库的人们更容易,需要将早先用不同的哲学完成的代码整合起来,或者由你没有联系的人来完成。 (即供应商 - 项目公司 - 不管没有更多,没有任何支持)。

    - 需要使用第三方API,服务和网站的人员。

    如果你仔细观察,这与之前的案例没有什么不同 - 第三方API,服务,网站就像外部隔离的代码库,你无法控制它们。 任何事情都可能发生。 因此,使用单例会话/用户类,您可以管理来自OpenID,Facebook,Twitter等第三方提供商的任何类型的会话/授权实现 - 并且您可以同时从SAME单例对象 - 在您插入任何代码的任何给定点上,可以在已知状态下轻松访问。 您甚至可以在您自己的网站/应用程序中为同一用户创建多个会话,以访问多个不同的第三方API /服务,并执行您想要的任何操作。

    当然,所有这些也可以通过使用普通的类和对象与传统的方法保持一致 - 这里的问题是,单例更整齐,更整洁,因此与传统的类/对象使用相比,可管理/可测试更容易。

    - 需要快速发展的人

    类似于全局的单例行为可以更容易地构建任何类型的代码,而该框架可以构建单体集合,因为一旦构建好单例类,已建立的,成熟的和已设置的方法将很容易获得并且可随时随地以一致的方式使用。 这需要一段时间才能成熟你的课程,但在此之后,它们坚如磐石,一贯而且有用。 你可以在任何你想要的单例中拥有尽可能多的方法,尽管这可能会增加对象的内存占用量,但它为快速开发所需的时间带来了更多的节省 - 在给定的一个实例中你没有使用的方法一个应用程序可以用在另一个集成的应用程序中,你可以通过一些修改来拍一个客户/老板/项目经理提出的新功能。

    你明白了。 现在让我们继续讨论单身人士的反对意见,以及邪恶的东西讨论有用的东西

    - 最首要的反对意见是它使测试更加困难。

    事实上,它确实在某种程度上,即使可以通过采取适当的预防措施并将调试例程编码到单例中来轻松缓解这一问题,但意识到您将调试单例。 但是请注意,这与其他任何编码理念/方法/模式都没有太大差别 - 只是单身人士相对较新而且并不普遍,所以目前的测试方法最终与它们不相容。 但是,这在编程语言的任何方面都没有什么不同 - 不同的风格需要不同的方法。

    有一点,这种反对意见是平淡的,它忽略了这样一个事实,即应用程序开发的原因不是为了'测试',而且测试不是进入应用程序开发的唯一阶段/过程。 应用程序开发用于生产用途。 正如我在'谁需要单身人士'一节中解释的那样,单身人士可以将复杂的代码作为内部代码库/应用程序/第三方服务的代码工作。 测试中可能会丢失的时间是在开发和部署中获得的时间。 这在第三方认证/应用/整合时代尤其有用 - Facebook,Twitter,OpenID等等,谁知道接下来会发生什么。

    虽然这是可以理解的 - 程序员根据他们的职业在不同的情况下工作。 对于那些在规模较大的公司工作的人来说,他们可以轻松地以不同的方式定义软件/应用程序,并且不会出现预算削减/裁员即将到来的厄运,而且需要做大量不同的东西一种廉价/快速/可靠的时尚,单身可能看起来并不那么必要。 它们甚至可能妨碍他们已经拥有的东西。

    但对于那些需要在“敏捷”开发的肮脏环境中工作的人来说,他们不得不从客户/经理/项目实施许多不同的请求(有时是不合理的),由于前面解释的原因,单身人士是节约的宽限。

    - 另一个反对意见是它的内存占用更高

    因为每个客户端的每个请求都会存在一个新的单例,所以这可能是PHP的一个反对意见。 如果构造和使用的单例非常糟糕,那么如果应用程序在任何给定的点上为许多用户提供服务,应用程序的内存占用量可能会更高。

    尽管如此,这对编码事物时可以采取的任何方法都是有效的。 应该问的问题是方法,这些单身人士所持有和处理的数据是不必要的? 因为如果它们在应用程序获得的许多请求中是必需的,那么即使你不使用单例,这些方法和数据也会以某种形式出现在你的应用程序中。 因此,当你将一个传统的类对象初始化为代码处理的三分之一并将其摧毁3/4时,这一切都成为你将要保存多少内存的问题。

    看这个问题时,这个问题变得毫不相关 - 不应该有不必要的方法,代码中的对象中保存着数据ANYway - 不管你使用的是单例还是不单单。 因此,这种对单身人士的反对变得非常有趣,因为它假设将会有不必要的方法,从您使用的类中创建对象中的数据。

    - 一些无效的反对意见,例如“维护多个数据库连接不可能/更难”

    当所有人都需要维护多个数据库连接,多个数据库选择,多个数据库查询,给定单例中的多个结果集时,只要将它们保存在单例中的变量/数组中,我甚至无法理解这种反对意见他们是需要的。 这可以像保持数组一样简单,尽管你可以发明任何你想用来实现的方法。 但让我们来看一下最简单的情况,在给定的单例中使用变量和数组:

    想象下面是在给定的数据库单例内:

    $ this - > connections = array (); (错误的语法,我只是这样键入它给你的图片 - 变量的正确声明是public $ connections = array();它的用法自然是$ this-> connections ['connectionkey'])

    您可以按照这种方式在任何给定时间设置并保持多个连接。 查询,结果集等也是如此。

    $ this - > query(QUERYSTRING,'queryname',$ this-> connections ['particulrconnection']);

    它可以通过选定的连接对选定的数据库执行查询,并将其存储在您的数据库中

    $ this - >结果

    数组与关键字'queryname'。 当然,你需要为你的查询方法编码 - 这是微不足道的。

    这使您能够尽可能多地保持不同的数据库连接和结果集(尽可能多地限制资源限制)。 并且它们可以在任何给定点上的任何一段代码中使用,该代码库中已经实例化了这个单例类。

    OF COURSE,你自然需要在不需要的时候释放结果集和连接 - 但不言而喻,它不是特定于单身人士或任何其他编码方法/风格/概念。

    在这一点上,您可以看到如何在同一个单例中维护与第三方应用程序或服务的多个连接/状态。 没有那么不同。

    长话短说,最后,单身模式只是另一种编程的方法/风格/哲学,当它们以正确的方式在正确的位置使用时,它们与任何其他方法一样有用。 这与任何东西都没有什么不同。

    你会注意到,在大多数单身人士遭受攻击的文章中,你也会看到“全局”的引用是“邪恶的”。

    让我们面对它 - 任何使用不当,滥用,误用,邪恶的东西。 这不限于任何语言,任何编码概念,任何方法。 无论何时你看到某人发布诸如'X is evil'之类的一揽子声明,都可以逃避那篇文章。 机会非常高,它是有限观点的产物 - 即使观点是多年经验的结果 - 通常最终是在特定的风格/方法中工作太多 - 典型的知识保守主义的结果​​。

    可以给出无数的例子,从“全球化是邪恶的”到“内部框架是邪恶的”。 大约10年前,甚至提议在任何给定的应用程序中使用iframe是异端邪说。 然后是Facebook,iframes到处都是,看看发生了什么 - iframe不再那么邪恶了。

    还有一些人固执地坚持认为自己是'邪恶'的 - 有时候也有很好的理由 - 但是,正如你所看到的那样,有需要的话,内联框架可以满足需求并且运作良好,因此整个世界都会继续前行。

    程序员/编码员/软件工程师最重要的资产是一个自由,开放和灵活的头脑。

    链接地址: http://www.djcxy.com/p/82187.html

    上一篇: case for singletons with database access in PHP?

    下一篇: Why is