null-object Об’єкт Null (англ. Null Object) - це об’єкт з певною нейтральною (“null”) поведінкою. Шаблон проєктування Null Object визначає використання таких об’єктів та його поведінку (чи її відсутність).

Null Object - не шаблон із книги Банди Чотирьох, але схема, яка з’являється досить часто, щоб вважатися шаблоном. Вона має такі переваги:

  • Клієнтський код спрощується;
  • Зменшує шанс винятків через нульові покажчики (та помилок PHP різного рівня);
  • Менше додаткових умов - менше тест кейсів.

Методи, які повертають об’єкт або Null, натомість мають повернути об’єкт NullObject. Це спрощений формальний код, який усуває необхідність перевірки if (!is_null($obj)) { $obj->callSomething(); }, замінюючи її на звичайний виклик $obj->callSomething();.

  • NullWorker.php
                  
    <?php
    
    namespace DesignPatterns\Behavioral\NullObject;
    
    class NullWorker implements WorkerInterface
    {
        const MSG = 'NULL OBJECT';
    
        public function isNull(): bool
        {
            return true;
        }
    
        public function makeSomethink()
        {
            return self::MSG;
        }
    }
    
                  
  • Worker.php
                  
    <?php
    
    namespace DesignPatterns\Behavioral\NullObject;
    
    class Worker implements WorkerInterface
    {
        const MSG = 'Worker make somethink';
    
        public function isNull(): bool
        {
            return false;
        }
    
        public function makeSomethink()
        {
            return self::MSG;
        }
    }
    
                  
  • WorkerInterface.php
                  
    <?php
    
    namespace DesignPatterns\Behavioral\NullObject;
    
    interface WorkerInterface
    {
        public function isNull(): bool;
        public function makeSomethink();
    }
    
                  
  • WorkerPool.php
                  
    <?php
    
    namespace DesignPatterns\Behavioral\NullObject;
    
    class WorkerPool
    {
        /**
         * @var WorkerInterface[]
         */
        protected $pool = [];
    
        public function __construct(...$workers)
        {
            $this->pool = $workers;
        }
    
        public function getPool(int $key): WorkerInterface
        {
            return $this->pool[$key] ?? new NullWorker();
        }
    
        public function makeSomethink(int $key = null)
        {
            return $this->getPool($key)->makeSomethink();
        }
    }
    
                  
  • Test case:

    WorkerPoolTest.php
      
    <?php
    
    namespace DesignPatterns\Tests\Behavioral\NullObject;
    
    use DesignPatterns\Behavioral\NullObject\NullWorker;
    use DesignPatterns\Behavioral\NullObject\Worker;
    use DesignPatterns\Behavioral\NullObject\WorkerPool;
    
    class WorkerPoolTest extends \PHPUnit_Framework_TestCase
    {
        public function testNullObject()
        {
            $worker = new Worker();
            $pool = new WorkerPool($worker);
    
            $this->assertEquals(Worker::MSG, $pool->makeSomethink(0));
            $this->assertEquals(false, $worker->isNull());
            $this->assertEquals(false, $pool->getPool(0)->isNull());
            $this->assertEquals(NullWorker::MSG, $pool->makeSomethink(1));
            $this->assertEquals(true, $pool->getPool(1)->isNull());
        }
    }