技术头条 - 一个快速在微博传播文章的方式     搜索本站
您现在的位置首页 --> PHP --> Serialize/Unserialize破坏单例

Serialize/Unserialize破坏单例

浏览:1793次  出处信息

我们经常采用如下方式定义单列:

  1. class Singleton {
  2.     private static $instance = NULL;
  3.     /** 不容许直接调用构造函数 */
  4.     private function __construct() {
  5.     }
  6.     /** 不容许深度复制 */
  7.     private function __clone() {
  8.     }
  9.     public static function getInstance() {
  10.         if (NULL === self::$instance) {
  11.              self::$instance = new self();
  12.           }
  13.         return self::$instance;
  14.     }
  15. }

很多人都会记得对深度copy的保护, 但, 其实我们却疏忽了一点:

  1. $a = Singleton::getInstance();
  2. $b = unserialize(serialize($a));
  3. var_dump($a === $b);
  4. //bool(false)

呵呵, 可见还需要修补, 加上对序列化的保护:

  1. class Singleton {
  2.     private static $instance = NULL;
  3.     /** 不容许直接调用构造函数 */
  4.     private function __construct() {
  5.     }
  6.     /** 不容许深度复制 */
  7.     private function __clone() {
  8.     }
  9.     /** 不容许serialize */
  10.     private function __sleep() {
  11.     }
  12.     /** 不容许unserialize */
  13.     private function __wakeup() {
  14.     }
  15.     public static function getInstance() {
  16.         if (NULL === self::$instance) {
  17.              self::$instance = new self();
  18.           }
  19.         return self::$instance;
  20.     }
  21. }

然而, 有的时候我们是希望我们的单利类是能序列化的, 这个时候可以考虑如下的方式:

  1. class Singleton {
  2.     private static $instance = NULL;
  3.     /** 不容许直接调用构造函数 */
  4.     private function __construct() {
  5.     }
  6.     /** 不容许深度复制 */
  7.     private function __clone() {
  8.     }
  9.     public function __wakeup() {
  10.         self::$instance = $this;
  11.     }
  12.     /** 需要在单利切换的时候做清理工作 */
  13.     public function __destruct() {
  14.         self::$instance = NULL;
  15.     }
  16.     public static function getInstance() {
  17.         if (NULL === self::$instance) {
  18.             self::$instance = new self();
  19.         }
  20.         return self::$instance;
  21.     }
  22. }

请注意上面, 我们在wakeup的时候, 切换了当前的单例实例, 来实现在序列化/反序列化的时刻保证单例.

另外, 对于一些包含全局资源的单例类, 我们需要定义析构函数, 来在切换的过程中做资源回收工作.

现在, 请大家仔细看看, 然后想想这段代码有没有什么问题?

接着往下看, 这段代码在有些条件下, 可能会达不到我们预期的目标, 比如:

  1. $a = Singleton::getInstance();
  2. $a = unserialize(serialize($a));
  3. var_dump($a === Singleton::getInstance());
  4. //bool(false)

大家可以想想为什么这样,, 如果不想想的, 就看我的下一篇文章吧.

最后, 做个广告,,,, 在新浪微博关注我吧: http://t.sina.com.cn/laruence, :)

建议继续学习:

  1. 可序列化单例模式的遗留问题答案    (阅读:2710)
  2. Unserialize与Autoload    (阅读:2550)
  3. Python创建单例模式的三种方式    (阅读:1472)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
© 2009 - 2024 by blogread.cn 微博:@IT技术博客大学习

京ICP备15002552号-1