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

Alt Iterator UML Diagram

3.3.5. Code

You can also find this code on GitHub

Book.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Behavioral\Iterator;
  4.  
  5. class Book
  6. {
  7. /**
  8. * @var string
  9. */
  10. private $author;
  11.  
  12. /**
  13. * @var string
  14. */
  15. private $title;
  16.  
  17. public function __construct(string $title, string $author)
  18. {
  19. $this->author = $author;
  20. $this->title = $title;
  21. }
  22.  
  23. public function getAuthor(): string
  24. {
  25. return $this->author;
  26. }
  27.  
  28. public function getTitle(): string
  29. {
  30. return $this->title;
  31. }
  32.  
  33. public function getAuthorAndTitle(): string
  34. {
  35. return $this->getTitle().' by '.$this->getAuthor();
  36. }
  37. }

BookList.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Behavioral\Iterator;
  4.  
  5. class BookList implements \Countable, \Iterator
  6. {
  7. /**
  8. * @var Book[]
  9. */
  10. private $books = [];
  11.  
  12. /**
  13. * @var int
  14. */
  15. private $currentIndex = 0;
  16.  
  17. public function addBook(Book $book)
  18. {
  19. $this->books[] = $book;
  20. }
  21.  
  22. public function removeBook(Book $bookToRemove)
  23. {
  24. foreach ($this->books as $key => $book) {
  25. if ($book->getAuthorAndTitle() === $bookToRemove->getAuthorAndTitle()) {
  26. unset($this->books[$key]);
  27. }
  28. }
  29.  
  30. $this->books = array_values($this->books);
  31. }
  32.  
  33. public function count(): int
  34. {
  35. return count($this->books);
  36. }
  37.  
  38. public function current(): Book
  39. {
  40. return $this->books[$this->currentIndex];
  41. }
  42.  
  43. public function key(): int
  44. {
  45. return $this->currentIndex;
  46. }
  47.  
  48. public function next()
  49. {
  50. $this->currentIndex++;
  51. }
  52.  
  53. public function rewind()
  54. {
  55. $this->currentIndex = 0;
  56. }
  57.  
  58. public function valid(): bool
  59. {
  60. return isset($this->books[$this->currentIndex]);
  61. }
  62. }

3.3.6. Test

Tests/IteratorTest.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Behavioral\Iterator\Tests;
  4.  
  5. use DesignPatterns\Behavioral\Iterator\Book;
  6. use DesignPatterns\Behavioral\Iterator\BookList;
  7. use DesignPatterns\Behavioral\Iterator\BookListIterator;
  8. use DesignPatterns\Behavioral\Iterator\BookListReverseIterator;
  9. use PHPUnit\Framework\TestCase;
  10.  
  11. class IteratorTest extends TestCase
  12. {
  13. public function testCanIterateOverBookList()
  14. {
  15. $bookList = new BookList();
  16. $bookList->addBook(new Book('Learning PHP Design Patterns', 'William Sanders'));
  17. $bookList->addBook(new Book('Professional Php Design Patterns', 'Aaron Saray'));
  18. $bookList->addBook(new Book('Clean Code', 'Robert C. Martin'));
  19.  
  20. $books = [];
  21.  
  22. foreach ($bookList as $book) {
  23. $books[] = $book->getAuthorAndTitle();
  24. }
  25.  
  26. $this->assertEquals(
  27. [
  28. 'Learning PHP Design Patterns by William Sanders',
  29. 'Professional Php Design Patterns by Aaron Saray',
  30. 'Clean Code by Robert C. Martin',
  31. ],
  32. $books
  33. );
  34. }
  35.  
  36. public function testCanIterateOverBookListAfterRemovingBook()
  37. {
  38. $book = new Book('Clean Code', 'Robert C. Martin');
  39. $book2 = new Book('Professional Php Design Patterns', 'Aaron Saray');
  40.  
  41. $bookList = new BookList();
  42. $bookList->addBook($book);
  43. $bookList->addBook($book2);
  44. $bookList->removeBook($book);
  45.  
  46. $books = [];
  47. foreach ($bookList as $book) {
  48. $books[] = $book->getAuthorAndTitle();
  49. }
  50.  
  51. $this->assertEquals(
  52. ['Professional Php Design Patterns by Aaron Saray'],
  53. $books
  54. );
  55. }
  56.  
  57. public function testCanAddBookToList()
  58. {
  59. $book = new Book('Clean Code', 'Robert C. Martin');
  60.  
  61. $bookList = new BookList();
  62. $bookList->addBook($book);
  63.  
  64. $this->assertCount(1, $bookList);
  65. }
  66.  
  67. public function testCanRemoveBookFromList()
  68. {
  69. $book = new Book('Clean Code', 'Robert C. Martin');
  70.  
  71. $bookList = new BookList();
  72. $bookList->addBook($book);
  73. $bookList->removeBook($book);
  74.  
  75. $this->assertCount(0, $bookList);
  76. }
  77. }