pla*_*one 6 php singleton design-patterns
可能重复:
谁需要单身人士?
我想知道,在php脚本中使用Singletons有什么缺点.我使用它们很多,我有时无法理解对开发人员的批评.一些例子:
我有一个Request类:
消除POST,GET,COOKIE inputdata并使用它而不是全局数组 - 严格地和全局地.喜欢
$request = Request::getInstance();
$firstname = $request->post('firstname', $additionalFilters);
Run Code Online (Sandbox Code Playgroud)
每个请求始终只有一个请求.为什么在这种情况下使用单例是一个坏主意?
$ _SESSION也是如此:
我有一个Session类(Singleton),它代表$ _SESSION数组,因为只有一个会话,我全局使用它.
数据库
$mysql = DB::getInstance('mysql', 'dbname'); //pseudo
$sqlite = DB::getInstance('sqlite', 'dbname'); //pseudo
Run Code Online (Sandbox Code Playgroud)
对于每种类型的数据库,我只想要一个对象,而不是更多.在我看来,否则存在混乱的风险.
独特的行
此外,我经常使用类来表示/使用db表的唯一行.
$article = Article::getInstance($id);
$navigation = Navigation::getInstance($id);
Run Code Online (Sandbox Code Playgroud)
我认为这样做只会带来好处.我从不想要第二个对象代表一个独特的行.为什么单身人士这么糟糕呢?
事实上,大多数(几乎所有)我的类没有公共构造函数,但总是像getInstance($ id)或create()这样的静态方法,所以类本身处理可能的实例(这并不意味着它们都是单例根据定义)
所以我的问题是:有没有我还没有意识到的缺点.具体情况是单身怀疑者在对Singletons提出建议时的想法.
编辑:
现在,你有一个包装$ _POST的单例,但是如果你没有$ _POST,但又想用一个文件来输入呢?在这种情况下,如果您有一个抽象的输入类,并实例化一个POSTInput来通过发布的数据来管理输入,那将会更方便.
好的,有效的优点.我没有意识到这一点.特别是关于Request类的观点.
我仍怀疑这种方法.假设我有一个"功能"类,它执行一个具体的请求(如留言簿组件).在该类中,我想获得一个发送参数.所以我得到了我的单身Request实例
$req = Request::getInstance();
$message = $req->post('message');
Run Code Online (Sandbox Code Playgroud)
这样,只有我的功能对象关心Request类.
当我使用非单例方法时,我需要一个额外的类/函数来管理每个请求获得一个有效的请求对象.这样我的功能类不需要知道那个管理类,但在我看来仍然会出现依赖/问题:每次我创建一个功能对象的实例时,我有可能忘记设置一个请求对象.
当然,我可以在创建功能时定义非可选参数.但这在某个时候会导致参数过度杀伤.或不?
我认为单例不应该像在基于请求的架构(例如 PHP 或 ASP.NET(或任何你想要的))中那样受到负面报道。本质上,在常规程序中,该单例的生命周期可以是程序运行时的数月或数年:
int main()
{
while(dont_exit)
{
// do stuff
Singleton& mySingleton = Singleton::getInstance();
// use it
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
除了只是一个全局变量之外,很难用可能在单元测试中有用的单例来替换该单例。可能依赖于它的代码量(可能有数百个源文件)将该单例的使用与整个程序紧密结合在一起。
也就是说,在基于请求的场景(例如 PHP 页面或 ASP.NET 页面)的情况下,所有可调用代码无论如何都有效地包装在函数调用中。同样,他们混淆了全局变量(但在请求的上下文中),并防止被多次创建。
但我仍然主张反对使用它们。为什么?因为即使在您的单个请求的上下文中,所有内容都依赖于该实例并与该实例紧密耦合。当您想使用不同的请求对象测试不同的场景时会发生什么?假设您使用包含进行编码,您现在必须修改该调用的每个实例。如果您传递了对预先构造的 Request 类的引用,那么您现在可以做很酷的事情,例如通过简单地更改传递给其他函数的内容来提供类的模拟单元测试版本。您还使用这个通用 Request 对象将所有内容解耦。