2.11. Rigistry
2.11.1. Предназначение
За да се приложи централно хранилище за обекти, често използвани в цялото приложение, обикновено се реализира с помощта на абстрактен клас само със статични методи (или с помощта на Singleton модел). Не забравяйте, че това въвежда глобално състояние, което трябва да се избягва по всяко време! Вместо това го внедрете с помощта на инжекция на зависимост!
2.11.2. UML Диаграма

2.11.3. Код
Можете също да намерите този код в GitHub
Registry.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Structural\Registry;
6
7use InvalidArgumentException;
8
9abstract class Registry
10{
11 public const LOGGER = 'logger';
12
13 /**
14 * this introduces global state in your application which can not be mocked up for testing
15 * and is therefor considered an anti-pattern! Use dependency injection instead!
16 *
17 * @var Service[]
18 */
19 private static array $services = [];
20
21 private static array $allowedKeys = [
22 self::LOGGER,
23 ];
24
25 final public static function set(string $key, Service $value)
26 {
27 if (!in_array($key, self::$allowedKeys)) {
28 throw new InvalidArgumentException('Invalid key given');
29 }
30
31 self::$services[$key] = $value;
32 }
33
34 final public static function get(string $key): Service
35 {
36 if (!in_array($key, self::$allowedKeys) || !isset(self::$services[$key])) {
37 throw new InvalidArgumentException('Invalid key given');
38 }
39
40 return self::$services[$key];
41 }
42}
Service.php
1<?php
2
3namespace DesignPatterns\Structural\Registry;
4
5class Service
6{
7}
2.11.4. Тест
Tests/RegistryTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Structural\Registry\Tests;
6
7use InvalidArgumentException;
8use DesignPatterns\Structural\Registry\Registry;
9use DesignPatterns\Structural\Registry\Service;
10use PHPUnit\Framework\TestCase;
11
12class RegistryTest extends TestCase
13{
14 private Service $service;
15
16 protected function setUp(): void
17 {
18 $this->service = $this->getMockBuilder(Service::class)->getMock();
19 }
20
21 public function testSetAndGetLogger()
22 {
23 Registry::set(Registry::LOGGER, $this->service);
24
25 $this->assertSame($this->service, Registry::get(Registry::LOGGER));
26 }
27
28 public function testThrowsExceptionWhenTryingToSetInvalidKey()
29 {
30 $this->expectException(InvalidArgumentException::class);
31
32 Registry::set('foobar', $this->service);
33 }
34
35 /**
36 * notice @runInSeparateProcess here: without it, a previous test might have set it already and
37 * testing would not be possible. That's why you should implement Dependency Injection where an
38 * injected class may easily be replaced by a mockup
39 *
40 * @runInSeparateProcess
41 */
42 public function testThrowsExceptionWhenTryingToGetNotSetKey()
43 {
44 $this->expectException(InvalidArgumentException::class);
45
46 Registry::get(Registry::LOGGER);
47 }
48}