iterator Итератор (англ. Iterator) относится к классу шаблонов поведения. Используется в составных объектах. Предоставляет доступ к своим внутренним полям, не раскрывая их структуру.

Зачастую этот шаблон используется вместо массива объектов, чтобы не только предоставить доступ к элементам, но и наделить некоторой логикой. Это может быть ограничение доступа, сортировка или любая другая операция над множеством объектов.

Из коробки PHP, нам доступен интерфейс Iterator.

  • Метод Iterator->current() возвращает текущий элемент
  • Метод Iterator->next() перемещает указатель на следующий элемент
  • Метод Iterator->key() возвращает индекс текущего элемента
  • Метод Iterator->valid() проверяет, существует ли текущий элемент или нет
  • Метод Iterator->rewind() переводит указатель текущего элемента на первый
  • Worker.php
                  
    <?php
    
    namespace DesignPatterns\Behavioral\Iterator;
    
    /**
     * Class Worker
     * @package DesignPatterns\Behavioral\Iterator
     */
    class Worker
    {
        /**
         * @var string
         */
        protected $name;
    
        /**
         * Worker constructor.
         *
         * @param string $name
         */
        public function __construct(string $name)
        {
            $this->name = $name;
        }
    
        /**
         * @return string
         */
        public function getName(): string
        {
            return $this->name;
        }
    }
    
                  
  • WorkersList.php
                  
    <?php
    
    namespace DesignPatterns\Behavioral\Iterator;
    
    use Countable;
    use Iterator;
    
    /**
     * Class WorkersList
     * @package DesignPatterns\Behavioral\Iterator
     */
    class WorkersList implements Iterator, Countable
    {
    
        /**
         * @var Worker[]
         */
        protected $workers = [];
        /**
         * @var int
         */
        protected $currentIndex = 0;
    
        /**
         * @param Worker $worker
         */
        public function addWorker(Worker $worker)
        {
            $this->workers[] = $worker;
        }
    
        /**
         * @return Worker
         */
        public function current(): Worker
        {
            return $this->workers[$this->currentIndex];
        }
    
        /**
         * @return void
         */
        public function next()
        {
            $this->currentIndex++;
        }
    
        /**
         * @return int
         */
        public function key(): int
        {
            return $this->currentIndex;
        }
    
        /**
         * @return bool
         */
        public function valid(): bool
        {
            return isset($this->workers[$this->currentIndex]);
        }
    
        /**
         * @return void
         */
        public function rewind()
        {
            $this->currentIndex = 0;
        }
    
        /**
         * @return int
         */
        public function count(): int
        {
            return count($this->workers);
        }
    }
    
                  
  • Test case:

    IteratorTest.php
      
    <?php
    
    namespace DesignPatterns\Tests\Behavioral\Iterator;
    
    use DesignPatterns\Behavioral\Iterator\Worker;
    use DesignPatterns\Behavioral\Iterator\WorkersList;
    
    class IteratorTest extends \PHPUnit_Framework_TestCase
    {
        public function testWorkerGetName()
        {
            $name = 'TestName';
    
            $worker = new Worker($name);
            $this->assertEquals($name, $worker->getName());
        }
    
        public function testCountList()
        {
            $ivanWorker = new Worker('Ivan');
            $petrWorker = new Worker('Petr');
            $andreyWorker = new Worker('Andrey');
    
            $workersList = new WorkersList();
    
            $workersList->addWorker($ivanWorker);
            $workersList->addWorker($petrWorker);
            $workersList->addWorker($andreyWorker);
            $this->assertCount(3, $workersList);
        }
    
        public function testWorkersListKey()
        {
            $workersList = new WorkersList();
    
            $this->assertEquals(0, $workersList->key());
    
            $workersList->next();
            $this->assertEquals(1, $workersList->key());
    
            $workersList->next();
            $this->assertEquals(2, $workersList->key());
        }
    
        public function testWorkersListValid()
        {
            $ivanWorker = new Worker('Ivan');
            $petrWorker = new Worker('Petr');
            $andreyWorker = new Worker('Andrey');
    
            $workersList = new WorkersList();
    
            $workersList->addWorker($ivanWorker);
            $workersList->addWorker($petrWorker);
            $workersList->addWorker($andreyWorker);
    
            $this->assertEquals(true, $workersList->valid());
    
            $workersList->next();
            $this->assertEquals(true, $workersList->valid());
    
            $workersList->next();
            $this->assertEquals(true, $workersList->valid());
    
            $workersList->next();
            $this->assertEquals(false, $workersList->valid());
        }
    
        public function testWorkersListResetKey()
        {
            $workersList = new WorkersList();
    
            $this->assertEquals(0, $workersList->key());
    
            $workersList->next();
            $this->assertEquals(1, $workersList->key());
    
            $workersList->next();
            $this->assertEquals(2, $workersList->key());
    
            $workersList->rewind();
            $this->assertEquals(0, $workersList->key());
        }
    
        public function testWorkerListCurrentWorker()
        {
            $ivanWorker = new Worker('Ivan');
            $petrWorker = new Worker('Petr');
            $andreyWorker = new Worker('Andrey');
    
            $workersList = new WorkersList();
    
            $workersList->addWorker($ivanWorker);
            $workersList->addWorker($petrWorker);
            $workersList->addWorker($andreyWorker);
    
            $this->assertSame($ivanWorker, $workersList->current());
            $workersList->next();
            $this->assertSame($petrWorker, $workersList->current());
            $workersList->next();
            $this->assertSame($andreyWorker, $workersList->current());
            $workersList->rewind();
            $this->assertSame($ivanWorker, $workersList->current());
        }
    }