PHPerKaigi 2024

Интерфейс IteratorAggregate

(PHP 5, PHP 7, PHP 8)

Введение

Интерфейс для создания внешнего итератора.

Обзор интерфейсов

interface IteratorAggregate extends Traversable {
/* Методы */
}

Пример #1 Основы использования

<?php
class myData implements IteratorAggregate {
public
$property1 = "Первое общедоступное свойство";
public
$property2 = "Второе общедоступное свойство";
public
$property3 = "Третье общедоступное свойство";
public
$property4 = "";

public function
__construct() {
$this->property4 = "последнее свойство";
}

public function
getIterator(): Traversable {
return new
ArrayIterator($this);
}
}

$obj = new myData;

foreach(
$obj as $key => $value) {
var_dump($key, $value);
echo
"\n";
}
?>

Вывод приведённого примера будет похож на:

string(9) "property1"
string(56) "Первое общедоступное свойство"

string(9) "property2"
string(56) "Второе общедоступное свойство"

string(9) "property3"
string(56) "Третье общедоступное свойство"

string(9) "property4"
string(35) "последнее свойство"

Содержание

add a note

User Contributed Notes 5 notes

up
29
trumbull dot j at gmail dot com
6 years ago
It might seem obvious, but you can return a compiled generator from your IteratorAggregate::getIterator() implementation.

<?php
class Collection implements IteratorAggregate
{
private
$items = [];

public function
__construct($items = [])
{
$this->items = $items;
}

public function
getIterator()
{
return (function () {
while(list(
$key, $val) = each($this->items)) {
yield
$key => $val;
}
})();
}
}

$data = [ 'A', 'B', 'C', 'D' ];
$collection = new Collection($data);

foreach (
$collection as $key => $val) {
echo
sprintf("[%s] => %s\n", $key, $val);
}
?>
up
23
Tab Atkins
11 years ago
Note that, at least as of 5.3, you still aren't allowed to return a normal Array from getIterator().

In some places, the docs wrap the array into an ArrayObject and return that. DON'T DO IT. ArrayObject drops any empty-string keys on the floor when you iterate over it (again, at least as of 5.3).

Use ArrayIterator instead. I wouldn't be surprised if it didn't have its own set of wonderful bugs, but at the very least it works correctly when you use it with this method.
up
9
Martin Speer
4 years ago
You can use yield from in getIterator in recent PHP 7 versions:

<?php

class Example implements \IteratorAggregate
{
protected
$data = [];

public function
__construct(array $data)
{
$this->data = $data;
}

public function
getIterator()
{
yield from
$this->data;
}
}

$test = new Example([1, 2, 3]);

foreach (
$test as $node) {
echo
$test, PHP_EOL;
}

/*
* Outputs:
*
* 1
* 2
* 3
*/
?>
up
14
Lubaev.K
10 years ago
<?php
// IteratorAggregate
// Create indexed and associative arrays.

class myData implements IteratorAggregate {

private
$array = [];
const
TYPE_INDEXED = 1;
const
TYPE_ASSOCIATIVE = 2;

public function
__construct( array $data, $type = self::TYPE_INDEXED ) {
reset($data);
while( list(
$k, $v) = each($data) ) {
$type == self::TYPE_INDEXED ?
$this->array[] = $v :
$this->array[$k] = $v;
}
}

public function
getIterator() {
return new
ArrayIterator($this->array);
}

}

$obj = new myData(['one'=>'php','javascript','three'=>'c#','java',], /*TYPE 1 or 2*/ );

foreach(
$obj as $key => $value) {
var_dump($key, $value);
echo
PHP_EOL;
}

// if TYPE == 1
#int(0)
#string(3) "php"
#int(1)
#string(10) "javascript"
#int(2)
#string(2) "c#"
#int(3)
#string(4) "java"

// if TYPE == 2
#string(3) "one"
#string(3) "php"
#int(0)
#string(10) "javascript"
#string(5) "three"
#string(2) "c#"
#int(1)
#string(4) "java"
?>

Good luck!
up
-15
ribeirocfb at gmail dot com
8 years ago
Example of the Iterator Pattern

<?php

namespace DesignPaterns;

class
BookCollection implements \IteratorAggregate
{
private
$a_titles = array();

public function
getIterator()
{
return new
BookIterator($this);
}

public function
addTitle($string)
{
$this->a_titles[] = $string;
}

public function
getTitle($key)
{
if (isset(
$this->a_titles[$key])){
return
$this->a_titles[$key];
}
return
null;
}

public function
is_empty()
{
return empty(
$a_titles);
}
}

<?
php

namespace DesignPaterns;

class
BookIterator implements \Iterator
{
private
$i_position = 0;
private
$booksCollection;

public function
__construct(BookCollection $booksCollection)
{
$this->booksCollection = $booksCollection;
}

public function
current()
{
return
$this->booksCollection->getTitle($this->i_position);
}

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

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

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

public function
valid()
{
return !
is_null($this->booksCollection->getTitle($this->i_position));
}
}

<?
php require 'vendor/autoload.php';

use
DesignPaterns\BookCollection;

$booksCollection = new BookCollection();
$booksCollection->addTitle('Design Patterns');
$booksCollection->addTitle('PHP7 is the best');
$booksCollection->addTitle('Laravel Rules');
$booksCollection->addTitle('DHH Rules');

foreach(
$booksCollection as $book){
var_dump($book);
}

/* === Output ===
* string(15) "Design Patterns"
* string(16) "PHP7 is the best"
* string(13) "Laravel Rules"
* string(9) "DHH Rules"
*/
To Top