3.3. Iterator
3.3.1. Purpose
To make an object iterable and to make it appear like a collection of objects.
3.3.2. Examples
- to process a file line by line by just running over all lines (whichhave an object representation) for a file (which of course is anobject, too)
3.3.3. Note
Standard PHP Library (SPL) defines an interface Iterator which is bestsuited for this! Often you would want to implement the Countableinterface too, to allow count($object)
on your iterable object
3.3.4. UML Diagram
3.3.5. Code
You can also find this code on GitHub
Book.php
- <?php
- namespace DesignPatterns\Behavioral\Iterator;
- class Book
- {
- /**
- * @var string
- */
- private $author;
- /**
- * @var string
- */
- private $title;
- public function __construct(string $title, string $author)
- {
- $this->author = $author;
- $this->title = $title;
- }
- public function getAuthor(): string
- {
- return $this->author;
- }
- public function getTitle(): string
- {
- return $this->title;
- }
- public function getAuthorAndTitle(): string
- {
- return $this->getTitle().' by '.$this->getAuthor();
- }
- }
BookList.php
- <?php
- namespace DesignPatterns\Behavioral\Iterator;
- class BookList implements \Countable, \Iterator
- {
- /**
- * @var Book[]
- */
- private $books = [];
- /**
- * @var int
- */
- private $currentIndex = 0;
- public function addBook(Book $book)
- {
- $this->books[] = $book;
- }
- public function removeBook(Book $bookToRemove)
- {
- foreach ($this->books as $key => $book) {
- if ($book->getAuthorAndTitle() === $bookToRemove->getAuthorAndTitle()) {
- unset($this->books[$key]);
- }
- }
- $this->books = array_values($this->books);
- }
- public function count(): int
- {
- return count($this->books);
- }
- public function current(): Book
- {
- return $this->books[$this->currentIndex];
- }
- public function key(): int
- {
- return $this->currentIndex;
- }
- public function next()
- {
- $this->currentIndex++;
- }
- public function rewind()
- {
- $this->currentIndex = 0;
- }
- public function valid(): bool
- {
- return isset($this->books[$this->currentIndex]);
- }
- }
3.3.6. Test
Tests/IteratorTest.php
- <?php
- namespace DesignPatterns\Behavioral\Iterator\Tests;
- use DesignPatterns\Behavioral\Iterator\Book;
- use DesignPatterns\Behavioral\Iterator\BookList;
- use DesignPatterns\Behavioral\Iterator\BookListIterator;
- use DesignPatterns\Behavioral\Iterator\BookListReverseIterator;
- use PHPUnit\Framework\TestCase;
- class IteratorTest extends TestCase
- {
- public function testCanIterateOverBookList()
- {
- $bookList = new BookList();
- $bookList->addBook(new Book('Learning PHP Design Patterns', 'William Sanders'));
- $bookList->addBook(new Book('Professional Php Design Patterns', 'Aaron Saray'));
- $bookList->addBook(new Book('Clean Code', 'Robert C. Martin'));
- $books = [];
- foreach ($bookList as $book) {
- $books[] = $book->getAuthorAndTitle();
- }
- $this->assertEquals(
- [
- 'Learning PHP Design Patterns by William Sanders',
- 'Professional Php Design Patterns by Aaron Saray',
- 'Clean Code by Robert C. Martin',
- ],
- $books
- );
- }
- public function testCanIterateOverBookListAfterRemovingBook()
- {
- $book = new Book('Clean Code', 'Robert C. Martin');
- $book2 = new Book('Professional Php Design Patterns', 'Aaron Saray');
- $bookList = new BookList();
- $bookList->addBook($book);
- $bookList->addBook($book2);
- $bookList->removeBook($book);
- $books = [];
- foreach ($bookList as $book) {
- $books[] = $book->getAuthorAndTitle();
- }
- $this->assertEquals(
- ['Professional Php Design Patterns by Aaron Saray'],
- $books
- );
- }
- public function testCanAddBookToList()
- {
- $book = new Book('Clean Code', 'Robert C. Martin');
- $bookList = new BookList();
- $bookList->addBook($book);
- $this->assertCount(1, $bookList);
- }
- public function testCanRemoveBookFromList()
- {
- $book = new Book('Clean Code', 'Robert C. Martin');
- $bookList = new BookList();
- $bookList->addBook($book);
- $bookList->removeBook($book);
- $this->assertCount(0, $bookList);
- }
- }