3.6. Null Object

3.6.1. Purpose

NullObject is not a GoF design pattern but a schema which appearsfrequently enough to be considered a pattern. It has the followingbenefits:

  • Client code is simplified
  • Reduces the chance of null pointer exceptions
  • Fewer conditionals require less test cases
    Methods that return an object or null should instead return an object orNullObject. NullObjects simplify boilerplate code such asif (!is_null($obj)) { $obj->callSomething(); } to just$obj->callSomething(); by eliminating the conditional check inclient code.

3.6.2. Examples

  • Symfony2: null logger of profiler
  • Symfony2: null output in Symfony/Console
  • null handler in a Chain of Responsibilities pattern
  • null command in a Command pattern

3.6.3. UML Diagram

Alt NullObject UML Diagram

3.6.4. Code

You can also find this code on GitHub

Service.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Behavioral\NullObject;
  4.  
  5. class Service
  6. {
  7. /**
  8. * @var LoggerInterface
  9. */
  10. private $logger;
  11.  
  12. /**
  13. * @param LoggerInterface $logger
  14. */
  15. public function __construct(LoggerInterface $logger)
  16. {
  17. $this->logger = $logger;
  18. }
  19.  
  20. /**
  21. * do something ...
  22. */
  23. public function doSomething()
  24. {
  25. // notice here that you don't have to check if the logger is set with eg. is_null(), instead just use it
  26. $this->logger->log('We are in '.__METHOD__);
  27. }
  28. }

LoggerInterface.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Behavioral\NullObject;
  4.  
  5. /**
  6. * Key feature: NullLogger must inherit from this interface like any other loggers
  7. */
  8. interface LoggerInterface
  9. {
  10. public function log(string $str);
  11. }

PrintLogger.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Behavioral\NullObject;
  4.  
  5. class PrintLogger implements LoggerInterface
  6. {
  7. public function log(string $str)
  8. {
  9. echo $str;
  10. }
  11. }

NullLogger.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Behavioral\NullObject;
  4.  
  5. class NullLogger implements LoggerInterface
  6. {
  7. public function log(string $str)
  8. {
  9. // do nothing
  10. }
  11. }

3.6.5. Test

Tests/LoggerTest.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Behavioral\NullObject\Tests;
  4.  
  5. use DesignPatterns\Behavioral\NullObject\NullLogger;
  6. use DesignPatterns\Behavioral\NullObject\PrintLogger;
  7. use DesignPatterns\Behavioral\NullObject\Service;
  8. use PHPUnit\Framework\TestCase;
  9.  
  10. class LoggerTest extends TestCase
  11. {
  12. public function testNullObject()
  13. {
  14. $service = new Service(new NullLogger());
  15. $this->expectOutputString('');
  16. $service->doSomething();
  17. }
  18.  
  19. public function testStandardLogger()
  20. {
  21. $service = new Service(new PrintLogger());
  22. $this->expectOutputString('We are in DesignPatterns\Behavioral\NullObject\Service::doSomething');
  23. $service->doSomething();
  24. }
  25. }