单例模式

单例模式

  • 单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。

  • 不适用单例模式时:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Database
    {
    public $db = null;
    public function __construct($config = array())
    {
    $dsn = sprintf('mysql:host=%s;dbname=%s', $config['db_host'], $config['db_name']);
    $this->db = new PDO($dsn, $config['db_user'], $config['db_pass']);
    }
    }

    然后创建3个对象:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $config = array(
    'db_name' => 'test',
    'db_host' => 'localhost',
    'db_user' => 'root',
    'db_pass' => 'root'
    );

    $db1 = new Database($config);
    var_dump($db1);
    $db2 = new Database($config);
    var_dump($db2);
    $db3 = new Database($config);
    var_dump($db3);
  • 输出信息:

    1
    2
    3
    4
    5
    6
    object(Database)[1]
    public 'db' => object(PDO)[2]
    object(Database)[3]
    public 'db' => object(PDO)[4]
    object(Database)[5]
    public 'db' => object(PDO)[6]
  • 每次new操作都会实例化一次类,就会增加一个数据库的连接,占用内存也在不断增大。

  • 使用单例模式

  • 基类上限制,只能实例化一次,如果实例化过,直接返回。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    class Database
    {
    // 声明$instance为私有静态类型,用于保存当前类实例化后的对象
    private static $instance = null;
    // 数据库连接句柄
    private $db = null;

    // 构造方法声明为私有方法,禁止外部程序使用new实例化,只能在内部new
    private function __construct($config = array())
    {
    $dsn = sprintf('mysql:host=%s;dbname=%s', $config['db_host'], $config['db_name']);
    $this->db = new PDO($dsn, $config['db_user'], $config['db_pass']);
    }

    // 这是获取当前类对象的唯一方式
    public static function getInstance($config = array())
    {
    // 检查对象是否已经存在,不存在则实例化后保存到$instance属性
    if(self::$instance == null) {
    self::$instance = new self($config);
    }
    return self::$instance;
    }

    // 获取数据库句柄方法
    public function db()
    {
    return $this->db;
    }

    // 声明成私有方法,禁止克隆对象
    private function __clone(){}
    // 声明成私有方法,禁止重建对象
    private function __wakeup(){}
    }
  • 实例化使用单利模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $config = array(
    'db_name' => 'test',
    'db_host' => 'localhost',
    'db_user' => 'root',
    'db_pass' => 'root'
    );

    $db1 = Database::getInstance($config);
    var_dump($db1);
    $db2 = Database::getInstance($config);
    var_dump($db2);
    $db3 = Database::getInstance($config);
    var_dump($db3);
  • 输出信息: 获取到的资源ID都是一样的

    1
    2
    3
    4
    5
    6
    object(Database)[1]
    private 'db' => object(PDO)[2]
    object(Database)[1]
    private 'db' => object(PDO)[2]
    object(Database)[1]
    private 'db' => object(PDO)[2]
  • 总结:

    单例模式:单利模式在应用中最为常见。单利模式在运行时实例是唯一的,他们不允许被生成自身的副本。
    所以 __clone__wakeup等复制克隆对象的魔术方法建议声明为私有方法。
    单例模式特点4私1公:

  • 私有静态属性:

  1. private static $instance = null; //用以保存类的实例化
  2. private function __construct(){} // // 构造方法声明为私有方法,禁止外部程序使用new实例化,只能在内部new
  3. private function __clone(){}// // 声明成私有方法,禁止克隆对象
  4. private function __wakeup(){} // // 声明成私有方法,禁止重建对象
  • 公有属性:
1
2
3
4
5
6
7
8
9
//方法提供给外部本类的实例化对象
public static function getInstance()
{
if(self::$instance == null) {
self::$instance = new self();
}
return self::$instance;
}

构造方法私有,克隆方法私有,重建方法私有,一个公共静态方法。