prototype Прототип (англ. Prototype) - позволяет создавать новые объекты на основе некоторого объекта-прототипа при этом совсем необязательно знать, как необходимый объект устроен.

Пример, конечно не очень, но он покажет суть шаблона. Перед подачей, наши бургеры нужно сложить в коробки. Создание коробки привычным путем через new занимает много времени (в конструкторе мы эмулируем задержку в 1 секунду). Если нужны 10 - это 10 секунд, 100 - 100 секунд и т.д. Что нам мешает сделать один общий объект, а дальше его клонировать?

  • BoxPrototype.php
                  
    <?php
    
    namespace DesignPatterns\Creational\Prototype;
    
    /**
     * Class BoxPrototype
     * @package DesignPatterns\Creational\Prototype
     */
    class BoxPrototype
    {
        /**
         * @var string
         */
        protected $title;
    
        /**
         * BoxPrototype constructor.
         *
         * If TRUE === delay, init object created 1 sec.
         *
         * @param bool $delay
         */
        public function __construct($delay = false)
        {
            if (true === $delay) {
                sleep(1);
            }
        }
    
        /**
         * All classes have the magic method __clone.
         * Implement this method if you want to change the default behavior.
         */
        public function __clone()
        {
        }
    
        /**
         * @return string
         */
        public function getTitle(): string
        {
            return $this->title;
        }
    
        /**
         * @param string $title
         *
         * @return void
         */
        public function setTitle(string $title)
        {
            $this->title = $title;
        }
    }
    
                  
  • Test case:

    PrototypeTest.php
      
    <?php
    
    namespace DesignPatterns\Tests\Creational\Prototype;
    
    use DesignPatterns\Creational\Prototype\BoxPrototype;
    use PHPUnit_Framework_TestCase;
    
    class PrototypeTest extends PHPUnit_Framework_TestCase
    {
        public function testPerformanceGetBoxWithDelay()
        {
            $start = $this->getTime();
    
            for ($i = 0; $i < 15; $i++) {
                $box = new BoxPrototype(true);
                $box->setTitle('BOX#' . $i);
                $this->assertInstanceOf('DesignPatterns\Creational\Prototype\BoxPrototype', $box);
            }
    
            $finish = $this->getTime();
    
            return $finish - $start;
        }
    
        /**
         * @depends testPerformanceGetBoxWithDelay
         *
         * @param int $testPerformanceInitWithNew
         */
        public function testPerformanceGetBoxWithClone(int $testPerformanceInitWithNew)
        {
            $start = $this->getTime();
    
            $boxPrototype = new BoxPrototype(true);
    
            for ($i = 0; $i < 15; $i++) {
                $box = clone $boxPrototype;
                $box->setTitle('BOX#' . $i);
                $this->assertInstanceOf('DesignPatterns\Creational\Prototype\BoxPrototype', $box);
            }
    
            $finish = $this->getTime();
    
            $testPerformanceInitWithClone = $finish - $start;
    
            $this->assertGreaterThan($testPerformanceInitWithClone, $testPerformanceInitWithNew);
        }
    
        private function getTime()
        {
            return (int)microtime(true);
        }
    }