Kcko
4/11/2020 - 7:19 PM

20. Iterator

<?php
// Iterator

/*

Definice
--------

Návrhový vzor Iterator umožňuje sekvenčně přistupovat k prvkům složených objektů
bez zveřejnění jejich základní struktury.
Pro využití návrhového vzoru Iterator jsou nutné následující kroky:

1. Zvolit, zda má třída implementovat rozhraní Iterator, nebo rozhraní
IteratorAggregate.
2. Implementovat metody vyžadované zvoleným rozhraním.

*/

include '1.php';

class BookList implements \Iterator 
{
    protected $bookDefinitions = array();
    protected $books = array();
    protected $position = 0;

    public function __construct($csvFile)
    {
        if (!file_exists($csvFile)) 
        {
            throw new IOException();
        }

        $fp = fopen($csvFile, 'r');
        while (false != ($line = fgetcsv($fp, 1024, ';'))) {
            $this->bookDefinitions[] = array(
                'category' => $line[0],
                'pagecount' => $line[1]
            );
        }
    }

    public function getBook($position)
    {
        if ($position > count($this->bookDefinitions)) {
            throw new Exception();
        }
        if (!isset($this->books[$position])) {
            $this->books[$position] = new Book(
                $this->bookDefinitions[$position]['category'],
                $this->bookDefinitions[$position]['pagecount']
            );
        }
        return $this->books[$position];
    }

    public function countBooks()
    {
        return count($this->bookDefinitions);
    }
  
    public function current()
    {
        if (!isset($this->books[$this->position])) {
            $this->books[$this->position] = new Book(
                $this->bookDefinitions[$this->position]['category'],
                $this->bookDefinitions[$this->position]['pagecount']
            );
        }
        return $this->books[$this->position];
    }

    public function key()
    {
        return $this->position;
    }

    public function next()
    {
        $this->position++;
    }

    public function rewind()
    {
        $this->position = 0;
    }

    public function valid()
    {
        if ($this->position < count($this->bookDefinitions)) 
        {
            return true;
        }
        return false;
    }

}


$list = new BookList('ext/books.csv');

// 1
for ($j = 0; $j < $list->countBooks(); $j++) 
{
    $book = $list->getBook($j);
    printf("%d -> %s\n", $j, $book->getCategory());
}

echo PHP_EOL;

// 2
$list->rewind();
while ($list->valid()) 
{
    $position = $list->key();
    $book = $list->current();
    printf("%d -> %s\n", $position, $book->getCategory());
    $list->next();
}

echo PHP_EOL;

// 3
foreach($list as $position => $book) 
{
    printf("%d -> %s\n", $position, $book->getCategory());
}


// 4
class ListHelper 
{
    public static function displayBooks(\Traversable $list) 
    {
        foreach($list as $position => $book) 
        {
            printf("%d -> %s\n", $position, $book->getCategory());
        }
    }
}

echo PHP_EOL;

$list = new BookList('ext/books.csv');
ListHelper::displayBooks($list);


echo PHP_EOL;

// chceme iterator pouzit i na pole
$books = array(
    new Book('PC', '100'),
    new Book('MEDICINA', '400'),
    new Book('AUTO-MOTO', '350'),
);

// takhle to nejde bze to neni Traversable
//ListHelper::displayBooks($books);

// takhle to pujde
ListHelper::displayBooks(new ArrayIterator($books));