Skip to content
This repository has been archived by the owner on Oct 11, 2020. It is now read-only.

duplabe/php-iterators

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

20 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PHP Iterátorok

Gondoltam készítek egy részletes, de korántsem teljes leírást a PHP iterátorairól.

SPL

Az iterátorokkal kapcsolatos interfészek és osztályok az SPL (Standard PHP Library) csomagban találhatóak.

Iterator

A PHP-s iterátorok az Iterator interfészen alapulnak, azt implementálják. Sok érdekesség nincs benne, a szokásos iterátorokkal kapcsolatos metódusokat szedi össze: current, key, next, rewind, valid.

EmptyIterator

EmptyIterator

Üres iterátor.

ArrayIterator

ArrayIterator

Tömbökön és objektumokon iterálhatunk végig.

Példa:

class Example
{
    public $a;
    protected $b;
    private $_c;

    public function __construct($a, $b, $c)
    {
        $this->a = $a;
        $this->b = $b;
        $this->_c = $c;
    }
}

echo 'Iterate over an object', PHP_EOL;

$iterator = new ArrayIterator(new Example(1, 2, 3));

foreach ($iterator as $item)
{
    echo $item, PHP_EOL;
}

echo 'Iterate over an array', PHP_EOL;

$iterator = new ArrayIterator(array(1,2,3));

foreach ($iterator as $item)
{
    echo $item, PHP_EOL;
}

Kimenet:

Iterate over an object
1
Iterate over an array
1
2
3

IteratorIterator

IteratorIterator

A Traversable interfészt implementáló objektumokból iterátort csinál.

NoRewindIterator

NoRewindIterator

Iterator, amit nem lehet rewindolni, azaz, ha egyszer végigmentünk az összes elemen, nem lehet újra kezdeni az iterálást.

InfiniteIterator

InfiniteIterator

Olyan iterátor, amellyel a végtelenségig iterálhatunk az elemeken, nem kell a rewindot meghívnunk.

LimitIterator

LimitIterator

Egy iterátor elemeinek részhalmazán mehetünk végig. A konstruktorában egy iterátoron kivül megadhatunk egy offset és egy count paramétert is.

Példa:

$limitIterator = new LimitIterator(
    new ArrayIterator(range(0, 10)),
    5,
    3
);

foreach ($limitIterator as $item) {
    echo $item, PHP_EOL;
}

Kimenet:

5
6
7

FilterIterator

FilterIterator

A FilterIterator egy belső iterátor elemiből tud szűrni. A FilterIterator egy abstract osztály, amelyben egy darab abstract metódus van, az accept(). Az accept() visszatérési értéke boolean:

  • true esetén az iterator elfogadja az elemet
  • false esetén eldobja

Példa:

class OddFilterIterator extends FilterIterator
{

    public function accept()
    {
        $current = $this->current();

        return is_integer($current) && $current % 2;
    }

}

$iterator = new AppendIterator();
$iterator->append(new ArrayIterator(range(0, 10)));
$iterator->append(new ArrayIterator(array('a', 'b')));

$filterIterator = new OddFilterIterator($iterator);

foreach ($filterIterator as $item) {
    echo $item, PHP_EOL;
}

Kimenet:

1
3
5
7
9

AppendIterator

AppendIterator

Több belső iteratort tárol, és azokon megy végig, egymás után.

A getArrayIterator() egy ArrayIterator-ban visszaadja az összes belső iteratort.

Példa:

$iterator1 = new ArrayIterator(range(0, 3));
$iterator2 = new ArrayIterator(range(4, 6));

$appendIterator = new AppendIterator();
$appendIterator->append($iterator1);
$appendIterator->append($iterator2);

foreach ($appendIterator as $key => $value) {
    echo $key, ' => ', print_r($value, true), PHP_EOL;
}

echo PHP_EOL, 'getArrayIterator()', PHP_EOL, PHP_EOL;

foreach ($appendIterator->getArrayIterator() as $key => $value) {
    echo $key, ' => ', print_r($value, true), PHP_EOL;
}

Kimenet:

0 => 0
1 => 1
2 => 2
3 => 3
0 => 4
1 => 5
2 => 6

getArrayIterator()

0 => ArrayIterator Object
(
    [storage:ArrayIterator:private] => Array
        (
            [0] => 0
            [1] => 1
            [2] => 2
            [3] => 3
        )

)

1 => ArrayIterator Object
(
    [storage:ArrayIterator:private] => Array
        (
            [0] => 4
            [1] => 5
            [2] => 6
        )

)

MultipleIterator

MultipleIterator

Az AppendIterator-hoz hasonlóan itt is több iterátoron mehetünk végig, de kicsit másképpen. Minden belső iterátorból kivesz egy elemet, majd egy tömbben összegyűjtve adja vissza iterációnként.

Flagek:

  • MultipleIterator::MIT_KEYS_NUMERIC: a tömb numerikusan indexelt
  • MultipleIterator::MIT_KEYS_ASSOC: a tömb asszociatív. A kulcsok az iterátorok hozzáadásánál adhatóak meg (attachIterator).

A belső iterátorok elemszáma különböző lehet, ezért két flaggel állíthatjuk be, hogy mi történjen akkor, ha valamelyikből elfogynak az elemek:

  • MultipleIterator::MIT_NEED_ANY: annyi elemet ad vissza, amennyit tud, a hiányzó elemeket null-okkal tölti fel.
  • MultipleIterator::MIT_NEED_ALL: ha valamelyik iterátorból elfogynak az elemek, a MultipleIterator leáll.

Példa:

$arrayIterator1 = new ArrayIterator(array('1','2','3','4',));
$arrayIterator2 = new ArrayIterator(array('5','6','7',));
$arrayIterator3 = new ArrayIterator(array('8','9','10','11',));

$miterator = new MultipleIterator(
    MultipleIterator::MIT_KEYS_ASSOC | MultipleIterator::MIT_NEED_ALL
);
$miterator->attachIterator($arrayIterator1, 'foo');
$miterator->attachIterator($arrayIterator2, 'bar');
$miterator->attachIterator($arrayIterator3, 'baz');

foreach ($miterator as $item) {
    echo var_export($item, true), PHP_EOL;
}

Kimenet:

Array
(
    [foo] => 1
    [bar] => 5
    [baz] => 8
)
Array
(
    [foo] => 2
    [bar] => 6
    [baz] => 9
)
Array
(
    [foo] => 3
    [bar] => 7
    [baz] => 10
)

Példa:

$arrayIterator1 = new ArrayIterator(array('1','2','3','4',));
$arrayIterator2 = new ArrayIterator(array('5','6','7',));
$arrayIterator3 = new ArrayIterator(array('8','9','10','11',));

$miterator = new MultipleIterator(
    MultipleIterator::MIT_KEYS_NUMERIC | MultipleIterator::MIT_NEED_ANY
);
$miterator->attachIterator($arrayIterator1, 'foo');
$miterator->attachIterator($arrayIterator2, 'bar');
$miterator->attachIterator($arrayIterator3, 'baz');

foreach ($miterator as $item) {
    echo var_export($item, true), PHP_EOL;
}

Kimenet:

Array
(
    [0] => 1
    [1] => 5
    [2] => 8
)
Array
(
    [0] => 2
    [1] => 6
    [2] => 9
)
Array
(
    [0] => 3
    [1] => 7
    [2] => 10
)
Array
(
    [0] => 4
    [1] =>
    [2] => 11
)

DirectoryIterator

DirectoryIterator

Egy könyvtár elemein mehetünk végig vele. Az elemek SplFileInfo objektumok.

Könyvtár szerkezet az iterátorok bemutatására:

|-example/b
| \-example/b/b.txt
|-example/c
\-example/a
  |-example/a/e
  | \-example/a/e/e.txt
  |-example/a/a.txt
  \-example/a/d

Példa:

$iterator = new DirectoryIterator('example');

foreach ($iterator as $value) {
    echo $value->getFilename(), PHP_EOL;
}

Kimenet:

b
..
c
.
a

FilesystemIterator

FilesystemIterator

Hasonló a DirectoryIterator-hoz, abból öröklődik. A konstructor alap esetben az alábbi flageket kapja:

  • KEY_AS_PATHNAME
  • CURRENT_AS_FILEINFO
  • SKIP_DOTS

További flagek:

  • CURRENT_AS_PATHNAME: a current() az aktuális file elérésével tér vissza
  • CURRENT_AS_FILEINFO: a current() egy SplFileInfo objektummal tér vissza
  • CURRENT_AS_SELF: a current() az iterator-ral ($this) tér vissza
  • KEY_AS_PATHNAME: a key() az aktuális file elérésével tér vissza
  • KEY_AS_FILENAME: a key() az aktuális file nevével tér vissza
  • FOLLOW_SYMLINKS: a hasChildren() követi a linkeket
  • NEW_CURRENT_AND_KEY: ugyanaz mint a FilesystemIterator::KEY_AS_FILENAME | FilesystemIterator::CURRENT_AS_FILEINFO
  • SKIP_DOTS: átugorja a .-ot és a ..-ot
  • UNIX_PATHS: az elérési utakban /-t használ, a PHP-t futtató OS-től függetlenül (pl Windows-on is)

GlobIterator

GlobIterator

A glob() függvényhez hasonló funkcionalitással rendelkező iterátor.

RecursiveIteratorIterator

RecursiveIteratorIterator

A rekurzív iterátorokat "linearizálja", azaz nem kell a gyermekekkel foglalkozni (ellenőrizni, hogy van e, és ha igen, akkor azokon is végigmenni).

Három módon használható:

  • RecursiveIteratorIterator::LEAVES_ONLY: Csak a leveleken megy végig. Ez a default.
  • RecursiveIteratorIterator::SELF_FIRST - Minden elemen végig megy, a szülőkkel kezd.
  • RecursiveIteratorIterator::CHILD_FIRST: Minden elemen végig megy, a levelekkel kezd.

ParentIterator

ParentIterator

Segítségével RecursiveIterator-okból lehet kiszűrni azon elemeket, amelyeknek nincs gyermekük. A RecursiveDirectoryIterator példához visszanyúlva, listázzuk ki csak a könyvtárakat:

$directoryIterator = new RecursiveDirectoryIterator(
    'example',
    RecursiveDirectoryIterator::SKIP_DOTS
);
$treeIterator = new RecursiveTreeIterator(
	new ParentIterator($directoryIterator)
);
foreach ($treeIterator as $node) {
    echo $node . PHP_EOL;
};

Kimenet:

Az üres könyvtárakat azért mutatja, mert ugye minden könyvtárban van egy hivatkozás önmagára (.) és a szülő könyvtárra (..), tehát van gyerekük.

|-example/b
|-example/c
\-example/a
  |-example/a/e
  \-example/a/d

RecursiveDirectoryIterator

RecursiveDirectoryIterator

A DirectoryIterator-hoz hasonlóan itt is egy könyvtár elemein mehetünk végig, de rekurzívan.

Péda:

$directoryIterator = new RecursiveDirectoryIterator(
    'example',
    RecursiveDirectoryIterator::SKIP_DOTS
);
$treeIterator = new RecursiveTreeIterator(
    $directoryIterator
);
foreach ($treeIterator as $key => $node) {
    echo $node, PHP_EOL;
}

Kimenet:

|-example/b
| \-example/b/b.txt
|-example/c
\-example/a
  |-example/a/e
  | \-example/a/e/e.txt
  |-example/a/a.txt
  \-example/a/d

Rekurzív iterátorok

Szinte az összes (itt nem is említett) iterátornak van rekurzív párja:

  • RecursiveArrayIterator
  • RecursiveCachingIterator
  • RecursiveCallbackFilterIterator
  • RecursiveFilterIterator
  • RecursiveRegexIterator
  • RecursiveTreeIterator

A cikknek példákkal együtt van saját repoja: php-iterators

Lehet jönni forkolni, javítani, bővíteni :)