3.4. Iterator (Iterator)
3.4.1. Przeznaczenie
Umożliwienie sekwencyjnego dostępu do elementów zawartych w innym obiekcie, zwykle kontenerze lub liście.
3.4.2. Przykłady
Procesowanie pliku linia po linii. Zakładamy, że zarówno plik jak i każda linijka z tego pliku to osobny obiekt. Możemy w ten sposób iterować po wszystkich liniach (będących obiektami) danego pliku.
3.4.3. Uwagi
Biblioteka SPL (Standard PHP Library) dostępna w PHP posiada interfejs Iterator, który świetnie nadaje się do tego zadania. Bardzo często klasa, która implementuje interfejs Iterator implementuje również interfejs Countable (również z biblioteki SPL), który pozwala policzyć liczbę elementów wywołaniem funkcji count($object)
.
3.4.4. Diagram UML

3.4.5. Kod
Ten kod znajdziesz również na GitHub.
Book.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Behavioral\Iterator;
6
7class Book
8{
9 public function __construct(private string $title, private string $author)
10 {
11 }
12
13 public function getAuthor(): string
14 {
15 return $this->author;
16 }
17
18 public function getTitle(): string
19 {
20 return $this->title;
21 }
22
23 public function getAuthorAndTitle(): string
24 {
25 return $this->getTitle() . ' by ' . $this->getAuthor();
26 }
27}
BookList.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Behavioral\Iterator;
6
7use Countable;
8use Iterator;
9
10class BookList implements Countable, Iterator
11{
12 /**
13 * @var Book[]
14 */
15 private array $books = [];
16 private int $currentIndex = 0;
17
18 public function addBook(Book $book)
19 {
20 $this->books[] = $book;
21 }
22
23 public function removeBook(Book $bookToRemove)
24 {
25 foreach ($this->books as $key => $book) {
26 if ($book->getAuthorAndTitle() === $bookToRemove->getAuthorAndTitle()) {
27 unset($this->books[$key]);
28 }
29 }
30
31 $this->books = array_values($this->books);
32 }
33
34 public function count(): int
35 {
36 return count($this->books);
37 }
38
39 public function current(): Book
40 {
41 return $this->books[$this->currentIndex];
42 }
43
44 public function key(): int
45 {
46 return $this->currentIndex;
47 }
48
49 public function next(): void
50 {
51 $this->currentIndex++;
52 }
53
54 public function rewind(): void
55 {
56 $this->currentIndex = 0;
57 }
58
59 public function valid(): bool
60 {
61 return isset($this->books[$this->currentIndex]);
62 }
63}
3.4.6. Testy
Tests/IteratorTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Behavioral\Iterator\Tests;
6
7use DesignPatterns\Behavioral\Iterator\Book;
8use DesignPatterns\Behavioral\Iterator\BookList;
9use PHPUnit\Framework\TestCase;
10
11class 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->assertSame(
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->assertSame(
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}