1.7. 单例模式
注:单例模式可能被认为是一种“反模式”。为了获得更好的可测试性和可维护性,建议使用依赖注入。
1.7.1. 目标
让应用只存在一个对象的实例,处理所有的调用。
1.7.2. 例子
数据库连接器
日志记录器
应用程序的锁定文件(Lock file,理论上整个应用应该只有一个锁文件)
1.7.3. UML 图

1.7.4. 代码
你可以在 GitHub 上找到这些代码
Singleton.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Creational\Singleton;
6
7use Exception;
8
9final class Singleton
10{
11 private static ?Singleton $instance = null;
12
13 /**
14 * gets the instance via lazy initialization (created on first usage)
15 */
16 public static function getInstance(): Singleton
17 {
18 if (self::$instance === null) {
19 self::$instance = new self();
20 }
21
22 return self::$instance;
23 }
24
25 /**
26 * is not allowed to call from outside to prevent from creating multiple instances,
27 * to use the singleton, you have to obtain the instance from Singleton::getInstance() instead
28 */
29 private function __construct()
30 {
31 }
32
33 /**
34 * prevent the instance from being cloned (which would create a second instance of it)
35 */
36 private function __clone()
37 {
38 }
39
40 /**
41 * prevent from being unserialized (which would create a second instance of it)
42 */
43 public function __wakeup()
44 {
45 throw new Exception("Cannot unserialize singleton");
46 }
47}
1.7.5. 测试
Tests/SingletonTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Creational\Singleton\Tests;
6
7use DesignPatterns\Creational\Singleton\Singleton;
8use PHPUnit\Framework\TestCase;
9
10class SingletonTest extends TestCase
11{
12 public function testUniqueness()
13 {
14 $firstCall = Singleton::getInstance();
15 $secondCall = Singleton::getInstance();
16
17 $this->assertInstanceOf(Singleton::class, $firstCall);
18 $this->assertSame($firstCall, $secondCall);
19 }
20}