3.7. Объект Null (Null Object)
3.7.1. Назначение
NullObject не шаблон из книги Банды Четырёх, но схема, которая появляется достаточно часто, чтобы считаться паттерном. Она имеет следующие преимущества:
Клиентский код упрощается
Уменьшает шанс исключений из-за нулевых указателей (и ошибок PHP различного уровня)
Меньше дополнительных условий — значит меньше тесткейсов
Методы, которые возвращают объект или Null, вместо этого должны вернуть объект NullObject
. Это упрощённый формальный код, устраняющий необходимость проверки if (!is_null($obj)) { $obj->callSomething(); }
, заменяя её на обычный вызов $obj->callSomething();
.
3.7.2. Примеры
Объекты Null-логгер или Null-вывод поддерживают стандартный вид взаимодействий между объектами, даже если они ничего не делают
Null-обработчик в шаблоне Цепочка Обязанностей (Chain of Responsibilities)
Null-команда в шаблоне Команда (Command)
3.7.3. Диаграмма UML
3.7.4. Код
Вы можете найти этот код на GitHub
Service.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Behavioral\NullObject;
6
7class Service
8{
9 public function __construct(private Logger $logger)
10 {
11 }
12
13 /**
14 * do something ...
15 */
16 public function doSomething()
17 {
18 // notice here that you don't have to check if the logger is set with eg. is_null(), instead just use it
19 $this->logger->log('We are in ' . __METHOD__);
20 }
21}
Logger.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Behavioral\NullObject;
6
7/**
8 * Key feature: NullLogger must inherit from this interface like any other loggers
9 */
10interface Logger
11{
12 public function log(string $str);
13}
PrintLogger.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Behavioral\NullObject;
6
7class PrintLogger implements Logger
8{
9 public function log(string $str)
10 {
11 echo $str;
12 }
13}
NullLogger.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Behavioral\NullObject;
6
7class NullLogger implements Logger
8{
9 public function log(string $str)
10 {
11 // do nothing
12 }
13}
3.7.5. Тест
Tests/LoggerTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Behavioral\NullObject\Tests;
6
7use DesignPatterns\Behavioral\NullObject\NullLogger;
8use DesignPatterns\Behavioral\NullObject\PrintLogger;
9use DesignPatterns\Behavioral\NullObject\Service;
10use PHPUnit\Framework\TestCase;
11
12class LoggerTest extends TestCase
13{
14 public function testNullObject()
15 {
16 $service = new Service(new NullLogger());
17 $this->expectOutputString('');
18 $service->doSomething();
19 }
20
21 public function testStandardLogger()
22 {
23 $service = new Service(new PrintLogger());
24 $this->expectOutputString('We are in DesignPatterns\Behavioral\NullObject\Service::doSomething');
25 $service->doSomething();
26 }
27}