是否有使用 PHP 访问数据库的单身人士的用例?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4595964/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 13:38:00  来源:igfitidea点击:

Is there a use-case for singletons with database access in PHP?

phpoopdesign-patternssingleton

提问by seriousdev

I access my MySQL database via PDO. I'm setting up access to the database, and my first attempt was to use the following:

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

The first thing I thought of is global:

我首先想到的是global

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

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

This is considered a bad practice. After a little search, I ended up with the Singleton pattern, which

这被认为是一种不好的做法。经过一番搜索,我最终得到了Singleton 模式,它

"applies to situations in which there needs to be a single instance of a class."

“适用于需要一个类的单个实例的情况。”

According to the example in the manual, we should do this:

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

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();

Why do I need that relatively large class when I can do this?

当我可以这样做时,为什么我需要那个相对较大的类?

class Database {
    private static $db;

    private function __construct(){}

    static 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() {
    Database::get()->query('...');
}

some_function();

This last one works perfectly and I don't need to worry about $dbanymore.

最后一个效果很好,我不需要再担心$db了。

How can I create a smaller singleton class, or is there a use-case for singletons that I'm missing in PHP?

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

采纳答案by Bill K

Okay, I wondered over that one for a while when I first started my career. Implemented it different ways and came up with two reasons to choose not to use static classes, but they are pretty big ones.

好吧,当我第一次开始我的职业生涯时,我想过一段时间。以不同的方式实现它并提出了两个选择不使用静态类的原因,但它们非常重要。

One is that you will find that very often something that you are absolutely sure that you'll never have more than one instance of, you eventually have a second. You may end up with a second monitor, a second database, a second server--whatever.

一个是你会发现很多时候你绝对确定你永远不会有超过一个实例的东西,你最终会有第二个。您最终可能会得到第二个监视器、第二个数据库、第二个服务器——不管怎样。

When this happens, if you have used a static class you're in for a much worse refactor than if you had used a singleton. A singleton is an iffy pattern in itself, but it converts fairly easily to an intelligent factory pattern--can even be converted to use dependency injection without too much trouble. For instance, if your singleton is gotten through getInstance(), you can pretty easily change that to getInstance(databaseName) and allow for multiple databases--no other code changes.

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

The second issue is testing (And honestly, this is the same as the first issue). Sometimes you want to replace your database with a mock database. In effect this is a second instance of the database object. This is much harder to do with static classes than it is with a singleton, you only have to mock out the getInstance() method, not every single method in a static class (which in some languages can be very difficult).

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

It really comes down to habits--and when people say "Globals" are bad, they have very good reasons to say so, but it may not always be obvious until you've hit the problem yourself.

这真的归结为习惯——当人们说“全球性”不好时,他们有很好的理由这么说,但在你自己解决问题之前,这可能并不总是显而易见的。

The best thing you can do is ask (like you did) then make a choice and observe the ramifications of your decision. Having the knowledge to interpret your code's evolution over time is much more important than doing it right in the first place.

你能做的最好的事情就是询问(就像你所做的那样)然后做出选择并观察你的决定的后果。拥有解释代码随时间演变的知识比一开始就正确执行要重要得多。

回答by Gordon

Singletons have very little - if not to say no - use in PHP.

单身人士在 PHP 中几乎没有 - 如果不是说不 - 使用。

In languages where objects live in shared memory, Singletons can be used to keep memory usage low. Instead of creating two objects, you reference an existing instance from the globally shared application memory. In PHP there is no such application memory. A Singleton created in one Request lives for exactly that request. A Singleton created in another Request done at the same time is still a completely different instance. Thus, one of the two main purposes of a Singleton is not applicable here.

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

In addition, many of the objects that can conceptually exist only once in your application do not necessarily require a language mechanism to enforce this. If you needonly one instance, then don't instantiate another. It's only when you may have noother instance, e.g. when kittens die when you create a second instance, that you might have a valid Use Case for a Singleton.

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

The other purpose would be to have a global access point to an instance within the same Request. While this might sound desirable, it really isnt, because it creates coupling to the global scope (like any globals and statics). This makes Unit-Testing harderand your application in general less maintainable. There is ways to mitigate this, but in general, if you need to have the same instance in many classes, use Dependency Injection.

另一个目的是在同一个请求中拥有一个对实例的全局访问点。虽然这听起来可能是可取的,但实际上并非如此,因为它会导致与全局作用域的耦合(就像任何全局变量和静态变量一样)。这使得单元测试更加困难,并且您的应用程序通常更难维护。有一些方法可以缓解这种情况,但一般来说,如果您需要在许多类中拥有相同的实例,请使用Dependency Injection

See my slides for Singletons in PHP - Why they are bad and how you can eliminate them from your applicationsfor additional information.

请参阅我的关于PHP中的单例的幻灯片- 为什么它们不好以及如何从应用程序中消除它们以获取更多信息。

Even Erich Gamma, one of the Singleton pattern's inventors, doubts this pattern nowadays:

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

"I'm in favor of dropping Singleton. Its use is almost always a design smell"

“我赞成放弃 Singleton。它的使用几乎总是一种设计味道”

Further reading

进一步阅读

If, after the above, you still need help deciding:

如果在上述之后,您仍然需要帮助决定:

Singleton Decision Diagram

单例决策图

回答by unity100

Who needs singletons in PHP?

谁需要 PHP 中的单身人士?

Notice that almost all of the objections to singletons come from technical standpoints - but they are also VERY limited in their scope. Especially for PHP. First, I will list some of the reasons for using singletons, and then I will analyze the objections to usage of singletons. First, people who need them:

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

- People who are coding a large framework/codebase, which will be used in many different environments, will have to work with previously existing, different frameworks/codebases, with the necessity of implementing many different, changing, even whimsical requests from clients/bosses/management/unit leaders do.

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

See, the singleton pattern is self inclusive. When done, a singleton class is rigid across any code you include it in, and it acts exactly like how you created its methods and variables. And it is always the same object in a given request. Since it cannot be created twice to be two different objects, you know what a singleton object is at any given point in a code - even if the singleton is inserted to two, three different, old, even spaghetti codebases. Therefore, it makes it easier in terms of development purposes - even if there are many people working in that project, when you see a singleton being initialized in one point in any given codebase, you know what it is, what it does, how it does, and the state it is in. If it was the traditional class, you would need to keep track of where was that object first created, what methods were invoked in it until that point in the code, and its particular state. But, drop a singleton there, and if you dropped proper debugging and information methods and tracking into the singleton while coding it, you know exactly what it is. So therefore, it makes it easier for people who have to work with differing codebases, with the necessity of integrating code which was done earlier with different philosophies, or done by people who you have no contact with. (that is, vendor-project-company-whatever is there no more, no support nothing).

看,单例模式是自包含的。完成后,单例类在您包含它的任何代码中都是刚性的,它的行为与您创建其方法和变量的方式完全相同。它始终是给定请求中的相同对象。因为它不能被创建两次成为两个不同的对象,所以你知道在代码中的任何给定点单例对象是什么——即使单例被插入到两个、三个不同的、旧的、甚至是意大利面条式的代码库中。因此,它使开发目的变得更容易 - 即使有很多人在该项目中工作,当您看到在任何给定代码库中的某一点初始化单例时,您就知道它是什么,它做什么,如何是,以及它所处的状态。如果它是传统类,则需要跟踪该对象首次创建的位置,在代码中的那个点之前调用了哪些方法,以及它的特定状态。但是,在那里放置一个单例,如果您在编码时删除了适当的调试和信息方法并跟踪到单例中,您就会确切地知道它是什么。因此,它使必须使用不同代码库的人更容易,并且需要集成之前使用不同哲学完成的代码,或者由您没有接触过的人完成的代码。(也就是说,供应商-项目-公司-无论什么都没有了,什么都不支持)。它使必须使用不同代码库的人更容易,并且需要集成之前使用不同哲学完成的代码,或者由您没有接触过的人完成的代码。(也就是说,供应商-项目-公司-无论什么都没有了,什么都不支持)。它使必须使用不同代码库的人更容易,并且需要集成之前使用不同哲学完成的代码,或者由您没有接触过的人完成的代码。(也就是说,供应商-项目-公司-无论什么都没有了,什么都不支持)。

- People who need to work with third-party APIs, services and websites.

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

If you look closer, this is not too different than the earlier case - third-party APIs, services, websites, are just like external, isolated codebases over which you have NO control. Anything can happen. So, with a singleton session/user class, you can manage ANY kind of session/authorization implementation from third-party providers like OpenID, Facebook, Twitterand many more - and you can do these ALL at the same time from the SAME singleton object - which is easily accessible, in a known state at any given point in whatever code you plug it into. You can even create multiple sessions to multiple different, third-party APIs/services for the SAME user in your own website/application, and do whatever you want to do with them.

如果仔细观察,这与之前的情况并没有太大区别——第三方 API、服务、网站就像外部的、孤立的代码库一样,您无法控制。任何事情都可能发生。因此,使用单例会话/用户类,您可以管理来自第三方提供商(如OpenIDFacebookTwitter等)的任何类型的会话/授权实现- 您可以从 SAME 单例对象同时执行这些操作- 易于访问,在您插入的任何代码中的任何给定点都处于已​​知状态。您甚至可以在您自己的网站/应用程序中为同一用户创建多个不同的第三方 API/服务的多个会话,并使用它们做任何您想做的事情。

Of course, all of this also can be tone with traditional methods by using normal classes and objects - the catch here is, singleton is tidier, neater and therefore because of that manageable/testable easier compared to traditional class/object usage in such situations.

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

- People who need to do rapid development

- 需要快速发展的人

The global-like behavior of singletons make it easier to build any kind of code with a framework which has a collection of singletons to build on, because once you construct your singleton classes well, the established, mature and set methods will be easily available and usable anywhere, anytime, in a consistent fashion. It takes some time to mature your classes, but after that, they are rock solid and consistent, and useful. You can have as many methods in a singleton doing whatever you want, and, though this may increase the memory footprint of the object, it brings much more savings in time required for rapid development - a method you are not using in one given instance of an application can be used in another integrated one, and you can just slap a new feature which client/boss/project manager asks just by a few modifications.

单例的全局行为使得使用具有可构建单例集合的框架更容易构建任何类型的代码,因为一旦您构建好单例类,建立的、成熟的和设置的方法将很容易获得并且随时随地以一致的方式使用。使您的类成熟需要一些时间,但在那之后,它们坚如磐石、一致且有用。您可以在一个单例中拥有尽可能多的方法来做任何您想做的事情,虽然这可能会增加对象的内存占用,但它可以节省更多快速开发所需的时间 - 您在一个给定的实例中没有使用的方法一个应用程序可以在另一个集成应用程序中使用,您只需进行一些修改即可获得客户/老板/项目经理要求的新功能。

You get the idea. Now lets move on to the objections to singletons and the unholy crusade against something that is useful:

你明白了。现在让我们继续反对单身人士和反对有用的东西的邪恶运动

- Foremost objection is that it makes testing harder.

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

And really, it does to some extent, even if it can be easily mitigated by taking proper precautions and coding debugging routines into your singletons WITH the realization that you will be debugging a singleton. But see, this isnt too different than ANY other coding philosophy/method/pattern that is out there - it's just that, singletons are relatively new and not widespread, so the current testing methods are ending up comparably incompatible with them. But that is not different in any aspect of programming languages - different styles require different approaches.

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

One point this objection falls flat in that, it ignores the fact that the reasons applications developed is not for 'testing', and testing is not the only phase/process that goes into an application development. Applications are developed for production use. And as I explained in the 'who needs singletons' section, singletons can cut a GREAT deal from the complexity of having to make a code work WITH and INSIDE many different codebases/applications/third-party services. The time which may be lost in testing, is time gained in development and deployment. This is especially useful in this era of third-party authentication/application/integration - Facebook, Twitter, OpenID, many more and who knows what's next.

有一点是,这种反对意见是平淡的,它忽略了这样一个事实,即开发应用程序不是为了“测试”的原因,并且测试不是进入应用程序开发的唯一阶段/过程。应用程序是为生产用途而开发的。正如我在“谁需要单身人士”部分所解释的那样,单身人士可以大大降低必须使代码与许多不同的代码库/应用程序/第三方服务一起工作并在其内部工作的复杂性。在测试中可能会损失的时间是在开发和部署中获得的时间。这在第三方身份验证/应用程序/集成时代尤其有用——Facebook、Twitter、OpenID 等等,谁知道接下来会发生什么。

Though it is understandable - programmers work in very different circumstances depending on their career. And for people who work in relatively big companies with defined departments tending different, defined software/applications in a comfortable fashion and without the impending doom of budget cuts/layoffs and the accompanying need to do a LOT of stuff with a lot of different stuff in a cheap/fast/reliable fashion, singletons may not seem so necessary. And it may even be nuisance/impediment to what they ALREADY have.

虽然这是可以理解的 - 程序员根据他们的职业在非常不同的环境中工作。对于那些在相对大的公司工作的人来说,他们有明确的部门,以一种舒适的方式管理不同的、明确的软件/应用程序,并且没有迫在眉睫的预算削减/裁员以及随之而来的需要做很多不同的事情的需要一种廉价/快速/可靠的时尚,单身人士似乎没有那么必要。它甚至可能对他们已经拥有的东西造成滋扰/障碍。

But for those who needs to work in the dirty trenches of 'agile' development, having to implement many different requests (sometimes unreasonable) from their client/manager/project, singletons are a saving grace due to reasons explained earlier.

但是对于那些需要在“敏捷”开发的肮脏战壕中工作的人来说,必须从他们的客户/经理/项目中实现许多不同的请求(有时是不合理的),由于前面解释的原因,单例是一种可取之处。

- Another objection is that its memory footprint is higher

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

Because a new singleton will exist for each request from each client, this MAY be an objection for PHP. With badly constructed and used singletons, the memory footprint of an application can be higher if many users are served by the application at any given point.

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

Though, this is valid for ANY kind of approach you can take while coding things. The questions which should be asked are, are the methods, data which are held and processed by these singletons unnecessary? For, if they ARE necessary across many of the requests application is getting, then even if you don't use singletons, those methods and data WILL be present in your application in some form or another through the code. So, it all becomes a question of how much memory will you be saving, when you initialize a traditional class object 1/3 into the code processing, and destroy it 3/4 into it.

不过,这对于您在编码时可以采用的任何类型的方法都是有效的。应该问的问题是,这些单身人士持有和处理的方法、数据是否不必要?因为,如果它们在应用程序收到的许多请求中是必需的,那么即使您不使用单例,这些方法和数据也会通过代码以某种形式出现在您的应用程序中。因此,当您将传统类对象 1/3 初始化到代码处理中,并将其销毁 3/4 时,这一切都变成了您将节省多少内存的问题。

See, when put this way, the question becomes quite irrelevant - there should not be unnecessary methods, data held in objects in your code ANYway - regardless of you use singletons or not. So, this objection to singletons becomes really hilarious in that, it ASSUMES that there will be unnecessary methods, data in the objects created from the classes you use.

看,当这样说时,问题变得无关紧要 - 无论如何都不应该有不必要的方法,代码中的对象中保存的数据 - 无论您是否使用单例。因此,这种对单例的反对变得非常有趣,因为它假设从您使用的类创建的对象中会有不必要的方法和数据。

- Some invalid objections like 'makes maintaining multiple database connnections impossible/harder'

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

I can't even begin to comprehend this objection, when all one needs to maintain multiple database connections, multiple database selections, multiple database queries, multiple result sets in a given singleton is just keeping them in variables/arrays in the singleton as long as they are needed. This can be as simple as keeping them in arrays, though you can invent whatever method you want to use to effect that. But let's examine the simplest case, use of variables and arrays in a given singleton:

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

Imagine the below is inside a given database singleton:

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

$this->connections = array(); (wrong syntax, I just typed it like this to give you the picture - the proper declaration of the variable is public $connections = array(); and its usage is $this->connections['connectionkey'] naturally )

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

You can set up, and keep multiple connections at any given time in an array in this fashion. And same goes for queries, result sets and so forth.

您可以在任何给定时间以这种方式在数组中设置和保持多个连接。查询、结果集等也是如此。

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

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

Which can just do a query to a selected database with a selected connection, and just store in your

它可以使用选定的连接对选定的数据库进行查询,然后将其存储在您的

$this->results

$this-> 结果

array with the key 'queryname'. Of course, you will need to have your query method coded for this - which is trivial to do.

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

This enables you to maintain a virtually infinite number of (as much as the resource limits allow of course) different database connections and result sets as much as you need them. And they are available to ANY piece of code in any given point in any given codebase into which this singleton class has been instantiated.

这使您能够根据需要维护几乎无限数量(当然,资源限制允许的数量)不同的数据库连接和结果集。并且它们可用于任何给定代码库中任何给定点的任何代码段,该单例类已实例化到其中。

OF COURSE, you would naturally need to free the result sets, and connections when not needed - but that goes without saying, and it's not specific to singletons or any other coding method/style/concept.

当然,您自然需要在不需要时释放结果集和连接 - 但这不言而喻,它并不特定于单例或任何其他编码方法/风格/概念。

At this point, you can see how you can maintain multiple connections/states to third-party applications or services in the same singleton. Not so different.

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

Long story short, in the end, singleton patterns are just another method/style/philosophy to program with, and they are as useful as ANY other when they are used in the correct place, in the correct fashion. Which is not different from anything.

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

You will notice that in most of the articles in which singletons are bashed, you will also see references to 'globals' being 'evil'.

您会注意到,在大多数抨击单身人士的文章中,您还会看到“全局”是“邪恶的”。

Let's face it - ANYthing that is not used properly, abused, misused, IS evil. That is not limited to any language, any coding concept, any method. Whenever you see someone issuing blanket statements like 'X is evil', run away from that article. Chances are very high that it's the product of a limited viewpoint - even if the viewpoint is the result of years of experience in something particular - which generally ends up being the result of working too much in a given style/method - typical intellectual conservatism.

让我们面对现实——任何使用不当、滥用、误用的东西都是邪恶的。这不限于任何语言、任何编码概念、任何方法。每当您看到有人发表诸如“X 是邪恶的”之类的笼统声明时,请远离该文章。很有可能它是有限观点的产物——即使观点是多年特定事物经验的结果——这通常最终是在给定的风格/方法中工作过多的结果——典型的知识分子保守主义。

Endless examples can be given for that, ranging from 'globals are evil' to 'iframes are evil'. Back around 10 years ago, even proposing the use of an iframe in any given application was heresy. Then comes Facebook, iframes everywhere, and look what has happened - iframes are not so evil anymore.

可以举出无数的例子,从“全局是邪恶的”到“iframe 是邪恶的”。回到大约 10 年前,即使提议在任何给定应用程序中使用 iframe 也是异端邪说。然后是 Facebook,到处都是 iframe,看看发生了什么——iframe 不再那么邪恶了。

There are still people who stubbornly insist that they are 'evil' - and sometimes for good reason too - but, as you can see, there is a need, iframes fill that need and work well, and therefore the entire world just moves on.

仍然有人顽固地坚持认为他们是“邪恶的”——有时也有充分的理由——但是,正如你所看到的,有一种需求,iframe 满足了这种需求并且运行良好,因此整个世界都在继续前进。

The foremost asset of a programmer/coder/software engineer is a free, open and flexible mind.

程序员/编码员/软件工程师最重要的资产是自由、开放和灵活的思想。

回答by Will Vousden

Singletons are considered by many to be anti-patternsas they're really just glorified global variables. In practice there are relatively few scenarios where it's necessaryfor a class to have only one instance; usually it's just that one instance is sufficient, in which case implementing it as a singleton is completely unnecessary.

许多人认为单例是反模式,因为它们实际上只是美化的全局变量。在实践中,有相对较少的场景中它是必要为一个类只有一个实例; 通常只是一个实例就足够了,在这种情况下,将其实现为单例是完全没有必要的。

To answer the question, you're right that singletons are overkill here. A simple variable or function will do. A better (more robust) approach, however, would be to use dependency injectionto remove the need for global variables altogether.

要回答这个问题,你是对的,单身人士在这里是矫枉过正。一个简单的变量或函数就可以了。然而,更好(更健壮)的方法是使用依赖注入来完全消除对全局变量的需求。

回答by Paul Sasik

In your example you're dealing with a single piece of seemingly unchanging information. For this example a Singleton would be overkill and just using a static function in a class will do just fine.

在您的示例中,您正在处理一条看似不变的信息。对于这个例子来说,单例会有点矫枉过正,只在类中使用静态函数就可以了。

More thoughts: You might be experiencing a case of implementing patterns for the sake of patterns and your gut is telling you "no, you don't have to" for the reasons you spelled out.

更多想法:您可能正在经历为了模式而实施模式的情况,并且出于您阐述的原因,您的直觉告诉您“不,您不必”。

BUT:We have no idea of the size and scope of your project. If this is simple code, perhaps throw away, that isn't likely to need to change then yes, go ahead and use static members. But, if you think that your project might need to scale or be prepped for maintenance coding down the road then, yes, you might want to use the Singleton pattern.

但是:我们不知道您项目的规模和范围。如果这是简单的代码,也许可以扔掉,那不太可能需要更改,那么是的,继续使用静态成员。但是,如果您认为您的项目可能需要扩展或为以后的维护编码做好准备,那么,是的,您可能想要使用单例模式。

回答by netcoder

First, I just want to say that I don't find much uses to the Singleton pattern. Why would one want to keep a single object thorough the whole application? Especially for databases, what if I want to connect to another database server? I have to disconnect and reconnect every time...? Anyway...

首先,我只想说我没有发现单例模式有多大用处。为什么要在整个应用程序中保留一个对象?特别是对于数据库,如果我想连接到另一个数据库服务器怎么办?我每次都必须断开连接并重新连接......?反正...

There are several drawbacks to using globals in an application (which is what the traditional use of the Singleton pattern does):

在应用程序中使用全局变量有几个缺点(这是单例模式的传统用法):

  • Difficult to unit test
  • Dependency injection issues
  • Can create locking issues (multi-threaded application)
  • 单元测试困难
  • 依赖注入问题
  • 可以创建锁定问题(多线程应用程序)

Use static classes instead of a singleton instance provides some of the same drawbacks as well, because the biggest problem of singleton is the static getInstancemethod.

使用静态类而不是单例实例也提供了一些相同的缺点,因为单例的最大问题是静态getInstance方法。

You can limit the number of instances a class can have without using the traditional getInstancemethod:

您可以在不使用传统getInstance方法的情况下限制类可以拥有的实例数:

class Single {

    static private $_instance = false;

    public function __construct() {
        if (self::$_instance)
           throw new RuntimeException('An instance of '.__CLASS__.' already exists');

        self::$_instance = true;
    }

    private function __clone() {
        throw new RuntimeException('Cannot clone a singleton class');
    }

    public function __destruct() {
        self::$_instance = false;
    }

}

$a = new Single;
$b = new Single; // error
$b = clone($a); // error
unset($a);
$b = new Single; // works

This will help on the first the points mentioned above: unit testing and dependency injection; while still making sure a single instance of the class exist in your application. You could, per example, just pass the resulting object to your models (MVC pattern) for them to use.

这将有助于解决上面提到的第一点:单元测试和依赖注入;同时仍然确保您的应用程序中存在该类的单个实例。例如,您可以将结果对象传递给您的模型(MVC 模式)供它们使用。

回答by Jon

Consider simply how your solution differs from the one presented in the PHP docs. In fact, there is just one "small" difference: your solution provides callers of the getter with a PDOinstance, while the one in the docs provides callers of Database::singletonwith a Databaseinstance (they then use the getter on that to get a PDOinstance).

简单地考虑一下您的解决方案与 PHP 文档中提供的解决方案有何不同。事实上,只有一个“小”区别:您的解决方案为 getter 的调用者提供了一个PDO实例,而文档中的解决方案为 的调用者提供Database::singleton了一个Database实例(然后他们使用 getter 来获取PDO实例)。

So what conclusion do we reach?

那么我们得出什么结论呢?

  • In the documentation code, callers get a Databaseinstance. The Databaseclass may expose (in fact, it shouldexpose if you 're going to all this trouble) a richer or higher-level interface than the PDOobject it wraps.
  • If you change your implementation to return another (richer) type than PDO, then the two implementations are equivalent. There's no gain to be had from following the manual implementation.
  • 在文档代码中,调用者获得一个Database实例。该Database班可暴露(事实上,它应该,如果你“重新去一切麻烦揭露),比一个富裕或更高级别的接口PDO它包装的对象。
  • 如果您更改您的实现以返回另一个(更丰富的)类型PDO,那么这两个实现是等效的。遵循手动实施没有任何好处。

On the practical side, Singleton is a pretty controversial pattern. This is mainly because:

在实践方面,单例模式是一个颇有争议的模式。这主要是因为:

  • It's overused. Novice programmers grok Singleton much easier than they grok other patterns. They then go on to apply their newfound knowledge everywhere, even if the problem at hand can be solved better without Singleton (when you 're holding a hammer, everything looks like a nail).
  • Depending on the programming language, implementing a Singleton in an airtight, non-leaky manner can prove to be a titanic task (especially if we have advanced scenarios: a singleton depending on another singleton, singletons that can be destroyed and re-created, etc). Just try to search for "the definitive" Singleton implementation in C++, I dare you (I own Andrei Alexandrescu's groundbreaking Modern C++ Design, which documents much of the mess).
  • It imposes additional workload both when coding the Singleton and when writing code to access it, workload which you can do without by following a few self-imposed constraints on what you try to do with your program variables.
  • 它被过度使用了。新手程序员理解 Singleton 比理解其他模式要容易得多。然后他们继续将他们新发现的知识应用到任何地方,即使手头的问题可以在没有 Singleton 的情况下更好地解决(当你拿着锤子时,一切看起来都像钉子)。
  • 根据编程语言,以密闭、无泄漏的方式实现单例可以证明是一项艰巨的任务(特别是如果我们有高级场景:单例依赖另一个单例,可以销毁和重新创建的单例等)。我敢于尝试在 C++ 中搜索“最终的”单例实现(我拥有 Andrei Alexandrescu 开创性的现代 C++ 设计,其中记录了大部分混乱)。
  • 它会在对 Singleton 进行编码和编写访问它的代码时施加额外的工作量,您可以通过遵循一些对您尝试使用程序变量执行的操作的自我强加约束来完成工作量。

So, as a final conclusion:your singleton is just fine. Not using Singleton at all is just fine most of the time as well.

所以,作为最后的结论:你的单身人士很好。大多数时候根本不使用 Singleton 也很好。

回答by Lightness Races in Orbit

Your interpretation is correct. Singletons have their place but are overused. Often, accessing static member functions is sufficient (notably, when you do not need to control time-of-construction in any way). Better, you can just put some free functions and variables in a namespace.

你的解释是正确的。单身人士有自己的位置,但被过度使用。通常,访问静态成员函数就足够了(特别是当您不需要以任何方式控制构造时间时)。更好的是,您可以将一些免费的函数和变量放在命名空间中。

回答by zzzzBov

When programming there is not "right" and "wrong"; there is "good practice" and "bad practice".

编程时没有“对”和“错”;有“好的做法”和“不好的做法”。

Singletons are generally created as a class to be reused later. They need to be created in such a way that the programmer doesn't accidentally instantiate two instances while drunkenly coding at midnight.

单例通常被创建为一个类,以便稍后重用。它们需要以这样一种方式创建,即程序员不会在午夜醉酒编码时意外实例化两个实例。

If you have a simple little class that shouldn'tbe instantiated more than once, you don't needto make it a singleton. It's just a safety net if you do.

如果您有一个不应被多次实例化的简单小类,则不需要将其设为单例。如果你这样做,它只是一个安全网。

it's not alwaysbad practice to have global objects. If you know that you're going to use it globally/everywhere/all the time, it may be one of the few exceptions. However, globals are generally considered "bad practice" in the same way that gotois considered bad practice.

拥有全局对象并不总是不好的做法。如果你知道你将在全球/任何地方/所有时间使用它,它可能是少数例外之一。然而,全局变量通常被认为是“坏习惯”,就像goto被认为是坏习惯一样。

回答by Kell

I don't see any point to this at all. If you implemented the class in such a way that the connection string was taken as a parameter to the constructor and maintained a list of PDOobjects (one for each unique connection string) then maybe there would be some benefit, but the implementation of singleton in this instance seems like a pointless exercise.

我根本看不出这有什么意义。如果您以将连接字符串作为构造函数的参数的方式实现类,并维护一个PDO对象列表(每个唯一的连接字符串一个),那么也许会有一些好处,但是单例的实现这个例子似乎是一个毫无意义的练习。