· 作者: Laruence( )
· 本文地址: http://www.laruence.com/2011/03/18/1909.html
· 转载请注明出处
我们经常采用如下方式定义单列:
1. class Singleton {
2. private static$instance = NULL;
3.
4. /** 不容许直接调用构造函数 */
5. private function__construct() {
6.
7. }
8.
9. /** 不容许深度复制 */
10. private function__clone() {
11. }
12.
13. public staticfunctiongetInstance() {
14. if (NULL === self::$instance) {
15. self::$instance = newself();
16. }
17.
18. return self::$instance;
19. }
20. }
很多人都会记得对深度copy的保护, 但, 其实我们却疏忽了一点:
1. <?php
2. $a = Singleton::getInstance();
3. $b = unserialize(serialize($a));
4.
5. var_dump($a === $b);
6. //bool(false)
呵呵, 可见还需要修补, 加上对序列化的保护:
1. class Singleton {
2. private static$instance = NULL;
3.
4. /** 不容许直接调用构造函数 */
5. private function__construct() {
6.
7. }
8.
9. /** 不容许深度复制 */
10. private function__clone() {
11. }
12.
13. /** 不容许serialize */
14. private function__sleep() {
15. }
16.
17. /** 不容许unserialize */
18. private function__wakeup() {
19. }
20.
21. public staticfunctiongetInstance() {
22. if (NULL === self::$instance) {
23. self::$instance = newself();
24. }
25.
26. return self::$instance;
27. }
28. }
然而, 有的时候我们是希望我们的单利类是能序列化的, 这个时候可以考虑如下的方式:
1. class Singleton {
2. private static$instance = NULL;
3.
4. /** 不容许直接调用构造函数 */
5. private function__construct() {
6.
7. }
8.
9. /** 不容许深度复制 */
10. private function__clone() {
11. }
12.
13. public function__wakeup() {
14. self::$instance = $this;
15. }
16.
17. /** 需要在单利切换的时候做清理工作 */
18. public function__destruct() {
19. self::$instance = NULL;
20. }
21.
22. public staticfunctiongetInstance() {
23. if (NULL === self::$instance) {
24. self::$instance = newself();
25. }
26.
27. return self::$instance;
28. }
29. }
请注意上面, 我们在wakeup的时候, 切换了当前的单例实例, 来实现在序列化/反序列化的时刻保证单例.
另外, 对于一些包含全局资源的单例类, 我们需要定义析构函数, 来在切换的过程中做资源回收工作.
现在, 请大家仔细看看, 然后想想这段代码有没有什么问题?
接着往下看, 这段代码在有些条件下, 可能会达不到我们预期的目标, 比如:
1. $a = Singleton::getInstance();
2. $a = unserialize(serialize($a));
3.
4. var_dump($a === Singleton::getInstance());
5. //bool(false)