mirror of
https://github.com/DesignPatternsPHP/DesignPatternsPHP.git
synced 2025-07-28 10:40:17 +02:00
Merge pull request #233 from domnikl/iterator-bug
#232 removed Iterator classes
This commit is contained in:
@@ -4,27 +4,33 @@ namespace DesignPatterns\Behavioral\Iterator;
|
||||
|
||||
class Book
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $author;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $title;
|
||||
|
||||
public function __construct($title, $author)
|
||||
public function __construct(string $title, string $author)
|
||||
{
|
||||
$this->author = $author;
|
||||
$this->title = $title;
|
||||
}
|
||||
|
||||
public function getAuthor()
|
||||
public function getAuthor(): string
|
||||
{
|
||||
return $this->author;
|
||||
}
|
||||
|
||||
public function getTitle()
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function getAuthorAndTitle()
|
||||
public function getAuthorAndTitle(): string
|
||||
{
|
||||
return $this->getTitle().' by '.$this->getAuthor();
|
||||
}
|
||||
|
@@ -2,16 +2,17 @@
|
||||
|
||||
namespace DesignPatterns\Behavioral\Iterator;
|
||||
|
||||
class BookList implements \Countable
|
||||
class BookList implements \Countable, \Iterator
|
||||
{
|
||||
private $books;
|
||||
/**
|
||||
* @var Book[]
|
||||
*/
|
||||
private $books = [];
|
||||
|
||||
public function getBook($bookNumberToGet)
|
||||
{
|
||||
if (isset($this->books[$bookNumberToGet])) {
|
||||
return $this->books[$bookNumberToGet];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $currentIndex = 0;
|
||||
|
||||
public function addBook(Book $book)
|
||||
{
|
||||
@@ -21,15 +22,41 @@ class BookList implements \Countable
|
||||
public function removeBook(Book $bookToRemove)
|
||||
{
|
||||
foreach ($this->books as $key => $book) {
|
||||
/** @var Book $book */
|
||||
if ($book->getAuthorAndTitle() === $bookToRemove->getAuthorAndTitle()) {
|
||||
unset($this->books[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->books = array_values($this->books);
|
||||
}
|
||||
|
||||
public function count()
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
@@ -1,86 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace DesignPatterns\Behavioral\Iterator;
|
||||
|
||||
class BookListIterator implements \Iterator
|
||||
{
|
||||
/**
|
||||
* @var BookList
|
||||
*/
|
||||
private $bookList;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $currentBook = 0;
|
||||
|
||||
public function __construct(BookList $bookList)
|
||||
{
|
||||
$this->bookList = $bookList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current book.
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.current.php
|
||||
*
|
||||
* @return Book Can return any type.
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->bookList->getBook($this->currentBook);
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Move forward to next element.
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.next.php
|
||||
*
|
||||
* @return void Any returned value is ignored.
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$this->currentBook++;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Return the key of the current element.
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.key.php
|
||||
*
|
||||
* @return mixed scalar on success, or null on failure.
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return $this->currentBook;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Checks if current position is valid.
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.valid.php
|
||||
*
|
||||
* @return bool The return value will be casted to boolean and then evaluated.
|
||||
* Returns true on success or false on failure.
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return null !== $this->bookList->getBook($this->currentBook);
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Rewind the Iterator to the first element.
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.rewind.php
|
||||
*
|
||||
* @return void Any returned value is ignored.
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->currentBook = 0;
|
||||
}
|
||||
}
|
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace DesignPatterns\Behavioral\Iterator;
|
||||
|
||||
class BookListReverseIterator implements \Iterator
|
||||
{
|
||||
/**
|
||||
* @var BookList
|
||||
*/
|
||||
private $bookList;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $currentBook = 0;
|
||||
|
||||
public function __construct(BookList $bookList)
|
||||
{
|
||||
$this->bookList = $bookList;
|
||||
$this->currentBook = $this->bookList->count() - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current book.
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.current.php
|
||||
*
|
||||
* @return Book Can return any type.
|
||||
*/
|
||||
public function current()
|
||||
{
|
||||
return $this->bookList->getBook($this->currentBook);
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Move forward to next element.
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.next.php
|
||||
*
|
||||
* @return void Any returned value is ignored.
|
||||
*/
|
||||
public function next()
|
||||
{
|
||||
$this->currentBook--;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Return the key of the current element.
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.key.php
|
||||
*
|
||||
* @return mixed scalar on success, or null on failure.
|
||||
*/
|
||||
public function key()
|
||||
{
|
||||
return $this->currentBook;
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Checks if current position is valid.
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.valid.php
|
||||
*
|
||||
* @return bool The return value will be casted to boolean and then evaluated.
|
||||
* Returns true on success or false on failure.
|
||||
*/
|
||||
public function valid()
|
||||
{
|
||||
return null !== $this->bookList->getBook($this->currentBook);
|
||||
}
|
||||
|
||||
/**
|
||||
* (PHP 5 >= 5.0.0)<br/>
|
||||
* Rewind the Iterator to the first element.
|
||||
*
|
||||
* @link http://php.net/manual/en/iterator.rewind.php
|
||||
*
|
||||
* @return void Any returned value is ignored.
|
||||
*/
|
||||
public function rewind()
|
||||
{
|
||||
$this->currentBook = $this->bookList->count() - 1;
|
||||
}
|
||||
}
|
@@ -4,8 +4,7 @@
|
||||
Purpose
|
||||
-------
|
||||
|
||||
To make an object iterable and to make it appear like a collection of
|
||||
objects.
|
||||
To make an object iterable and to make it appear like a collection of objects.
|
||||
|
||||
Examples
|
||||
--------
|
||||
@@ -45,18 +44,6 @@ BookList.php
|
||||
:language: php
|
||||
:linenos:
|
||||
|
||||
BookListIterator.php
|
||||
|
||||
.. literalinclude:: BookListIterator.php
|
||||
:language: php
|
||||
:linenos:
|
||||
|
||||
BookListReverseIterator.php
|
||||
|
||||
.. literalinclude:: BookListReverseIterator.php
|
||||
:language: php
|
||||
:linenos:
|
||||
|
||||
Test
|
||||
----
|
||||
|
||||
@@ -67,4 +54,4 @@ Tests/IteratorTest.php
|
||||
:linenos:
|
||||
|
||||
.. _`GitHub`: https://github.com/domnikl/DesignPatternsPHP/tree/master/Behavioral/Iterator
|
||||
.. __: http://en.wikipedia.org/wiki/Iterator_pattern
|
||||
.. __: http://en.wikipedia.org/wiki/Iterator_pattern
|
||||
|
@@ -9,66 +9,68 @@ use DesignPatterns\Behavioral\Iterator\BookListReverseIterator;
|
||||
|
||||
class IteratorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @var BookList
|
||||
*/
|
||||
protected $bookList;
|
||||
|
||||
protected function setUp()
|
||||
public function testCanIterateOverBookList()
|
||||
{
|
||||
$this->bookList = new BookList();
|
||||
$this->bookList->addBook(new Book('Learning PHP Design Patterns', 'William Sanders'));
|
||||
$this->bookList->addBook(new Book('Professional Php Design Patterns', 'Aaron Saray'));
|
||||
$this->bookList->addBook(new Book('Clean Code', 'Robert C. Martin'));
|
||||
}
|
||||
$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'));
|
||||
|
||||
public function expectedAuthors()
|
||||
{
|
||||
return array(
|
||||
array(
|
||||
array(
|
||||
'Learning PHP Design Patterns by William Sanders',
|
||||
'Professional Php Design Patterns by Aaron Saray',
|
||||
'Clean Code by 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
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider expectedAuthors
|
||||
*/
|
||||
public function testUseAIteratorAndValidateAuthors($expected)
|
||||
public function testCanIterateOverBookListAfterRemovingBook()
|
||||
{
|
||||
$iterator = new BookListIterator($this->bookList);
|
||||
$book = new Book('Clean Code', 'Robert C. Martin');
|
||||
$book2 = new Book('Professional Php Design Patterns', 'Aaron Saray');
|
||||
|
||||
while ($iterator->valid()) {
|
||||
$expectedBook = array_shift($expected);
|
||||
$this->assertEquals($expectedBook, $iterator->current()->getAuthorAndTitle());
|
||||
$iterator->next();
|
||||
$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
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider expectedAuthors
|
||||
*/
|
||||
public function testUseAReverseIteratorAndValidateAuthors($expected)
|
||||
public function testCanAddBookToList()
|
||||
{
|
||||
$iterator = new BookListReverseIterator($this->bookList);
|
||||
$book = new Book('Clean Code', 'Robert C. Martin');
|
||||
|
||||
while ($iterator->valid()) {
|
||||
$expectedBook = array_pop($expected);
|
||||
$this->assertEquals($expectedBook, $iterator->current()->getAuthorAndTitle());
|
||||
$iterator->next();
|
||||
}
|
||||
$bookList = new BookList();
|
||||
$bookList->addBook($book);
|
||||
|
||||
$this->assertCount(1, $bookList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test BookList Remove.
|
||||
*/
|
||||
public function testBookRemove()
|
||||
public function testCanRemoveBookFromList()
|
||||
{
|
||||
$this->bookList->removeBook($this->bookList->getBook(0));
|
||||
$this->assertEquals($this->bookList->count(), 2);
|
||||
$book = new Book('Clean Code', 'Robert C. Martin');
|
||||
|
||||
$bookList = new BookList();
|
||||
$bookList->addBook($book);
|
||||
$bookList->removeBook($book);
|
||||
|
||||
$this->assertCount(0, $bookList);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user