# 单例模式（Singleton）

## 概述:

单例模式（singleton）是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问，从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个，单例模式是最好的解决方案。

## 模式核心思想

* 1）保证一个类仅有一个实例；
* 2）它必须自行创建这个实例；
* 3）它必须自行向整个系统提供这个实例。

## 模式架构图:

## ![](https://2166326059-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LfnT30n_07ZN5S7w5Tb%2F-LfnT5w3Liyn75DIsY2n%2F-LfnT7VN5Mi3tsxKvytT%2F%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F%E6%9E%B6%E6%9E%84%E5%9B%BE.jpg?generation=1558862934671045\&alt=media)模式架构简单代码实现示例：

mysql单例示例:

```php
<?php
class Mysql
{
    //该属性用来保存实例
    private static $conn;
    //构造函数为private,防止外界实例化对象
    private function __construct()
    {
        $this->conn = mysql_connect('localhost','root','');
    }
    //创建一个用来实例化对象的方法
    public static function getInstance()
    {
        if (!(self::$conn instanceof self)) {
            self::$conn = new self;
        }
        return self::$conn;
    }
    //防止外界clone实例
    public function __clone(){
        trigger_error('Clone is not allowed !');
    }
}

//只能静态方式取得实例，不能new 和 clone
$mysql = Mysql::getInstance();
```

## 简单场景示例：

**场景：**&#x5047;设现在有一个保存项目应用信息的类AppInfo,我们可以用它来保存如项目名称、项目的网址、项目版本等。这些信息在你每次调用时候都可能有所不同。原因是它是可以被系统中其他无关对象进行设置。

如果我们使用传递类对象的方式实现，会产生耦合，而且还必须使所有的对象实例都使用的同一个AppInfo对象（保证数据一致）。

故如下代码：

```php
<?php
class AppInfo
{
    private $props = array();

    private static $instance;

    //防止外界实例化对象
    private function __construct()
    {
    }
    //防止外界clone实例
    private function __clone()
    {
    }AppInfo

    public static function getInstance()
    {
        if (empty(self::$instance)) {
            self::$instance = new self;
        }

        return self::$instance;
    }

    public function setProperty($key, $val)
    {
        $this->props[$key] = $val;
    }

    public function getProperty($key)
    {
        return $this->props[$key];
    }
}

$info = AppInfo::getInstance();
$info->setProperty("name","xiaoxiami");
unset($info);
$info2 = AppInfo::getInstance();
echo $info2->getProperty("name");//输出xiaoxiami  key为name的属性值并没有丢失。
```
