是否有一个用PHP的数据库访问的单身人士的使用情况?
我通过PDO访问我的MySQL数据库。 我设置了对数据库的访问权限,我的第一个尝试是使用以下内容:
我想到的第一件事是global
:
$db = new PDO('mysql:host=127.0.0.1;dbname=toto', 'root', 'pwd'); function some_function() { global $db; $db->query('...'); }
这被认为是不好的做法。 经过一番search,我结束了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级呢?
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
了。
我怎样才能创build一个较小的单例类,或者是我在PHP中缺less的单例的用例呢?
好吧,当我刚开始我的职业生涯的时候,我对这一段时间感到奇怪。 实现它不同的方式,并提出了两个select不使用静态类的原因,但他们是相当大的。
一个是,你经常会发现,你绝对肯定你永远不会有一个以上的事例,你最终还会有一个事例。 你可能会得到第二台显示器,第二台数据库,第二台服务器 – 无论如何。
当发生这种情况时,如果你使用了一个静态类,那么你的重构要比使用单例更糟糕。 单例本身就是一个不确定的模式,但是它很容易转换成一个智能的工厂模式 – 甚至可以被转换为使用dependency injection而没有太多的麻烦。 例如,如果你的单例是通过getInstance()获得的,你可以很容易地将其改为getInstance(databaseName),并允许多个数据库 – 没有其他代码改变。
第二个问题是testing(老实说,这和第一个问题是一样的)。 有时候你想用模拟数据库replace你的数据库。 实际上,这是数据库对象的第二个实例。 这对于静态类来说比用单例要难得多,你只需要嘲笑getInstance()方法,而不是静态类中的每一个方法(在某些语言中这是非常困难的)。
这真的归结为习惯 – 当人们说“全球化”是坏的时候,他们有很好的理由这么说,但是直到你自己解决问题才会显而易见。
你可以做的最好的事情就是问(就像你做的那样),然后做出select并观察决定的后果。 有了解释你的代码随着时间的变化的知识,比首先正确的做法更重要。
在PHP中,单身人士甚less – 如果不是说不用的话。
在共享内存中存在对象的语言中,可以使用单例来保持内存使用率较低。 您不必创build两个对象,而是从全局共享的应用程序内存中引用现有实例。 在PHP中没有这样的应用程序内存。 在一个请求中创build的单例生效的确切是这个请求。 在另一个同时完成的请求中创build的单例仍然是一个完全不同的实例。 因此,Singleton的两个主要目的之一在这里是不适用的。
另外,在应用程序中只能在概念上只存在一次的许多对象不一定需要语言机制来执行此操作。 如果只需要一个实例,则不要实例化另一个实例 。 只有当你没有其他的实例时,例如当你创build第二个实例的时候小猫死了,你可能拥有一个有效的Singleton用例。
另一个目的是在同一个请求中有一个全局接入点。 虽然这听起来可取,但它确实没有,因为它创build了耦合到全局范围(如任何全局和静态)。 这使得unit testing更难 ,你的应用程序通常不易维护。 有办法来减轻这一点,但一般来说,如果你需要在许多类中有相同的实例,使用dependency injection 。
在PHP中查看我的幻灯片单身人士 – 为什么他们是坏的,以及如何从您的应用程序中消除他们的额外信息。
即使是单身模式的发明者之一Erich Gamma ,现在也怀疑这种模式:
“我赞成丢弃Singleton,它的使用几乎总是一种devise味道”
进一步阅读
- 如何在PHP中testingregistry模式或单例?
- 使用PHP数据库类作为单例有什么缺点?
- 使用PHP PDO的数据库抽象类devise
- 单身人士会成为微博网站的一个很好的devise模式吗?
- 修改一个类来封装而不是inheritance
- 如何访问另一个类的对象?
- 为什么Singletons在PHP中没有用处
- 清洁法典会议 – 单身人士和全球国家
如果之后,你仍然需要帮助决定:
谁需要PHP中的单身人士?
请注意,几乎所有对单身人士的反对意见都来自技术立场 – 但他们的范围也非常有限。 特别是对于PHP。 首先,我将列举使用单身人士的一些原因,然后我将分析单身人士使用的反对意见。 首先,需要他们的人:
– 编写大型框架/代码库的人员将被用在许多不同的环境中,他们必须使用以前存在的,不同的框架/代码库,并且必须执行来自客户/老板的许多不同的,不断变化的甚至是异想天开的请求/pipe理/单位领导呢。
看,单身模式是自我包容的。 完成之后,单个类在你包含的任何代码中都是刚性的,它的行为就像你创build它的方法和variables一样。 在给定的请求中它总是相同的对象。 由于无法将两次创build为两个不同的对象,所以即使将单例插入到两个,三个不同的,旧的,甚至意大利面代码库中,也可以知道单个对象在代码中的任何给定位置。 因此,就开发目的而言,即使有很多人在这个项目中工作,当你看到一个singleton在任何给定的代码库中被初始化为一个点,你也知道它是什么,它做了什么,如果是传统的类,则需要跟踪该对象最先创build的位置,在该位置调用哪些方法,直到该位置为止,以及该对象的特定状态。 但是,在那里放弃一个单例,如果在编写代码的时候丢弃了适当的debugging和信息方法并追踪到单例,那么您确切知道它是什么。 因此,它使得那些需要使用不同代码库的人们更容易,需要将不同哲学早期完成的代码整合起来,或者由你们没有联系的人来完成。 (即供应商 – 项目公司 – 什么都没有,没有任何支持)。
– 需要使用第三方API ,服务和网站的人员。
如果仔细观察,这与前面的案例没有什么不同 – 第三方API,服务,网站就像外部隔离的代码库,您无法控制这些代码库。 任何事情都可能发生。 因此,使用单例会话/用户类,您可以pipe理来自OpenID , Facebook , Twitter等第三方提供者的任何种类的会话/授权实现 – 您可以同时从SAME单例对象 – 这是很容易获得的,在任何代码插入到任何给定的点在一个已知的状态。 您甚至可以在自己的网站/应用程序中为同一个用户创build多个不同的第三方API /服务的会话,并执行您想要的任何操作。
当然,所有这些也可以通过使用普通的类和对象与传统的方法调和 – 这里的问题是,单例更加整洁,整洁,因此相对于传统的类/对象在这种情况下更易于pipe理/testing。
– 需要快速发展的人
单态的类似全局的行为可以更容易地构build任何types的代码,并且有一个单独的集合构build的框架,因为一旦你构build好单例类,那么已经build立,成熟和设置的方法将会很容易获得,可以随时随地以一致的方式使用。 成熟你的课程需要一些时间,但在此之后,他们是坚如磐石的,一贯的,有用的。 你可以在任何你想要的单例中使用尽可能多的方法,尽pipe这可能会增加对象的内存占用,但是它为快速开发带来了更多的时间节省 – 在给定的一个实例中没有使用的方法一个应用程序可以在另一个集成的应用程序中使用,而且您可以通过一些修改来为客户/上司/项目经理提出一个新function。
你明白了。 现在让我们继续讨论对单身人士的反对意见,以及邪恶的东西讨论有用的东西 :
– 最主要的反对意见是它使testing更加困难。
实际上,它在某种程度上也是如此,即使通过采取适当的预防措施并将debugging例程编码到您的单例中,您也可以轻松地缓解这个问题。 但是请注意,这与其他任何编码原理/方法/模式都没有太大的区别 – 只是单身相对比较新而且并不普遍,所以目前的testing方法最终与它们不相容。 但是,这在编程语言的任何方面都没有什么不同 – 不同的风格需要不同的方法。
有一点,这种反对意见是平淡的,它忽略了应用程序开发的原因不是“testing”的事实,testing不是进入应用程序开发的唯一阶段/过程。 应用程序开发用于生产使用。 正如我在“谁需要单身人士”一节中解释的那样,单身人士可以从繁琐的代码工作和内部代码库/应用程序/第三方服务中解脱出来。 testing中可能会丢失的时间是在开发和部署中获得的时间。 这在第三方authentication/应用/整合 – Facebook,Twitter,OpenID等时代尤其有用,谁知道接下来会发生什么。
虽然这是可以理解的 – 程序员根据自己的职业在不同的情况下工作。 对于那些在规模较大的公司里工作的人来说,这些软件和应用程序可以很舒适的方式来处理,而且不会出现预算削减/裁员的情况,同时也需要做大量不同的东西一个廉价/快速/可靠的时尚,单身可能不是那么必要。 这甚至可能是他们已经拥有的滋扰/阻碍。
但是对于那些需要在“敏捷”开发的肮脏战略中工作的人来说,他们不得不从客户/经理/项目实施许多不同的请求(有时是不合理的),因为前面解释过的原因,单身人士是一种节约的优惠。
另一个反对意见是它的内存占用更高
因为每个客户端的每个请求都会存在一个新的单例,所以这可能是PHP的一个反对意见。 如果构造和使用的单例非常糟糕,那么如果应用程序在任何给定点上提供了许多用户,则应用程序的内存占用量可能会更高。
不过,这对于编码事物时可以采取的任何方法都是有效的。 应该问的问题是,这些单身人士所持有和处理的方法是不必要的? 因为,如果在应用程序正在获取的许多请求中它们是必需的,那么即使不使用单例,这些方法和数据也会通过代码以某种forms出现在您的应用程序中。 所以,当你将一个传统的类对象初始化为代码处理的1/3时,这个问题就变成了一个你将要保存多less内存的问题,并且把它摧毁3/4。
看这个问题的时候,这个问题变得毫不相关 – 不应该有不必要的方法,代码中的对象中保存的数据ANYway – 不pipe你使用的是单例还是不单单。 所以,这种对单身人士的反对变得非常有趣,因为它假定从您使用的类中创build的对象中将会有不必要的方法,数据。
– 一些无效的反对意见,如“维护多个数据库连接不可能/更难”
当所有人都需要维护多个数据库连接,多个数据库select,多个数据库查询,给定单例中的多个结果集时,只要将它们保存在单例中的variables/数组中,我甚至无法理解这种反对意见他们是需要的。 这可以像保持数组一样简单,尽pipe你可以发明任何你想用来实现的方法。 但让我们来看看最简单的情况,在给定的单例中使用variables和数组:
想象下面是在给定的数据库单例中:
$ this – > connections = array (); (错误的语法,我只是这样input给你的图片 – variables的正确声明是public $ connections = array();它的用法自然是$ this-> connections ['connectionkey'])
您可以设置,并在这种方式在任何给定的时间保持在一个数组中的多个连接。 查询,结果集等也是如此。
$ this – > query(QUERYSTRING,'queryname',$ this-> connections ['particulrconnection']);
哪一个可以用选定的连接对选定的数据库进行查询,并存储在你的
$ this – >结果
数组与关键字'queryname'。 当然,你将需要你的查询方法编码 – 这是微不足道的。
这使得您可以尽可能多地维护不同的数据库连接和结果集(尽可能多地限制资源限制)。 在任何给定的代码中,任何一个代码片段都可以使用这个singleton类的实例。
当然,你自然需要在不需要的时候释放结果集和连接 – 但这不言而喻,它不是特定于单例或任何其他编码方法/样式/概念。
在这一点上,你可以看到如何维护到同一个单身的第三方应用程序或服务的多个连接/状态。 没有那么不同
长话短说,最终,单身模式只是另一种编程的方法/风格/哲学,当它们以正确的方式在正确的地方使用时,它们与其他任何其他方法一样有用。 这与任何东西都没有什么不同。
你会注意到,在大多数单身人士被攻击的文章中,你也会看到“全局”的引用是“邪恶的”。
让我们面对它 – 任何使用不当,虐待,误用,邪恶的东西。 这不限于任何语言,任何编码概念,任何方法。 无论何时你看到有人发布“X是邪恶的”一揽子声明,都可以逃避那篇文章。 机会是非常高的,它是一个有限的观点的产物 – 即使这个观点是多年的经验的结果,特别是一个特定的风格/方法 – 通常是知识保守主义的结果。
可以给出无数的例子,从“全球化是邪恶”到“内在框架都是邪恶”。 大约10年前,甚至提出在任何给定的应用程序中使用iframe是异端。 接下来是Facebook,iframes到处都是,看看发生了什么 – iframe不再那么邪恶了。
还有一些人固执地坚持认为自己是“邪恶的” – 有时也是有原因的 – 但是,正如你所看到的,有必要,内联框架满足了这种需求,并且运作良好,因此整个世界都在继续前进。
程序员/编码员/软件工程师最重要的资产是一个自由,开放和灵活的头脑。
单身人士被许多人认为是反模式,因为他们真的只是荣耀的全球变数。 在实践中,相对较less的情况下,一个class级只有一个实例是必要的; 通常只有一个实例就足够了 ,在这种情况下,将它作为单例实现是完全没有必要的。
为了回答这个问题,你说得对,单身人士在这里是过度的。 一个简单的variables或函数将做。 然而,更好的(更强大的)方法是使用dependency injection来完全消除对全局variables的需求。
在你的例子中,你正在处理一个看似不变的信息。 对于这个例子来说,一个单例将是矫枉过正,只是在一个类中使用一个静态函数就可以了。
更多的想法:你可能正在经历一个为了模式而实施模式的案例,而你的直觉告诉你“不,你不必”,因为你阐述的理由。
但是:我们不知道你的项目的规模和范围。 如果这是简单的代码,也许扔掉,这是不太可能需要改变是的,继续前进,并使用静态成员。 但是,如果你认为你的项目可能需要扩展或者在维护编码方面做好准备,那么是的,你可能想要使用Singleton模式。
首先,我只想说,我没有发现Singleton模式的很多用途。 为什么要在整个应用程序中保留一个对象? 特别是对于数据库,如果我想连接到另一个数据库服务器呢? 我必须每次断开连接并重新连接…? 无论如何…
在应用程序中使用全局variables有几个缺点(这是Singleton模式的传统用法):
- 难以进行unit testing
- dependency injection问题
- 可以创buildlocking问题(multithreading应用程序)
使用静态类而不是单例实例也提供了一些相同的缺点,因为单例的最大问题是静态getInstance
方法。
您可以限制类可以使用的实例的数量,而无需使用传统的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
这将有助于上述第一点:unit testing和dependency injection; 同时仍然确保您的应用程序中存在单个类的实例。 举例来说,你可以将结果对象传递给你的模型(MVC模式)供他们使用。
考虑一下你的解决scheme与PHP文档中的解决scheme有什么不同。 实际上,只有一个“小”差异:你的解决scheme为getter的调用者提供了一个PDO
实例,而docs中的一个提供了Database::singleton
调用者与一个Database
实例(然后他们使用getter来实现得到一个PDO
实例)。
那么我们得出了什么结论呢?
- 在文档代码中,调用者获取一个
Database
实例。Database
类可能暴露(实际上,它应该公开,如果你要去所有这些麻烦)比它包装的PDO
对象更丰富或更高级别的接口。 - 如果你改变你的实现来返回比
PDO
更丰富的types,那么这两个实现是等价的。 遵循手动执行没有任何好处。
在实践方面,辛格尔顿是一个相当有争议的模式。 这主要是因为:
- 它被滥用。 新手程序员开发Singleton比他们挖掘其他模式容易得多。 然后,他们继续在各处应用新发现的知识,即使没有单身人士(当你拿着锤子,一切看起来像钉子),现在的问题可以更好地解决。
- 根据编程语言的不同,实现一个单一的气密,不泄漏的方式可以被certificate是一个巨大的任务(特别是如果我们有先进的scheme:单身人士取决于另一个单身人士,可以被破坏和重新创build的单身人士等)。 只要尝试在C ++中search“权威的”Singleton实现,我敢说(我拥有Andrei Alexandrescu的开创性的现代C ++devise,它logging了大部分的混乱)。
- 它在编写Singleton时以及编写代码访问时都会增加额外的工作量,通过遵循一些自己对你的程序variables的限制,你可以做的工作量。
所以,作为最后的结论:你的单身就好了。 大多数情况下,不使用Singleton也是好的。
你的解释是正确的。 单身人士有自己的位置,但被过度使用。 通常,访问静态成员函数是足够的(特别是,当你不需要以任何方式控制施工时间时)。 更好的是,你可以在命名空间中放一些免费的函数和variables。
编程时没有“正确”和“错误”; 有“良好做法”和“不良做法”。
单身人士通常被创build为一个class,以后再使用。 他们需要以这样的方式创build,程序员不会在午夜醉coding coding的时候不小心实例化两个实例。
如果你有一个简单的小类, 不应该被多次实例化,你不需要把它变成一个单例。 这只是一个安全网,如果你这样做。
拥有全局对象并不总是不好的做法。 如果你知道你将要在全球/无处不在的地方使用它,它可能是less数例外之一。 但是,全局variables通常被认为是“不好的做法”,就像goto
被认为是不好的做法一样。
我完全没有看到任何意见。 如果你以一种连接string作为构造函数参数的方式实现了这个类,并维护了一个PDO对象列表(每个唯一的连接string),那么也许会有一些好处,但是单例实现在这个例子似乎是一个毫无意义的练习。
据我所知,你不会错过任何东西。 这个例子很有缺陷。 如果单例类有一些非静态的实例variables,会有所不同。