Итератор (англ. 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());
}
}