SlideShare ist ein Scribd-Unternehmen logo
1 von 131
Looping the
Loop
with
SPL Iterators
Looping the Loop with SPL
Iterators
What is an Iterator?
An Iterator is an object that enables a programmer to
traverse a container, particularly lists.
A Behavioural Design Pattern (GoF)
Looping the Loop with SPL
Iterators
What is an Iterator?
$dataSet = ['A', 'B', 'C'];
foreach($dataSet as $key => $value) {
echo "{$key} => {$value}", PHP_EOL;
}
Looping the Loop with SPL
Iterators
What is an Iterator?
0 => A
1 => B
2 => C
Looping the Loop with SPL
Iterators
What is an Iterator?
$data = ['A', 'B', 'C'];
$dataSet = new ArrayIterator($data);
foreach($dataSet as $key => $value) {
echo "{$key} => {$value}", PHP_EOL;
}
Looping the Loop with SPL
Iterators
What is an Iterator?
0 => A
1 => B
2 => C
Looping the Loop with SPL
Iterators
What is an Iterator?
interface Iterator extends Traversable {
/* Methods */
abstract public current ( void ) : mixed
abstract public key ( void ) : scalar
abstract public next ( void ) : void
abstract public rewind ( void ) : void
abstract public valid ( void ) : bool
}
Looping the Loop with SPL
Iterators
What is an Iterator?
$data = ['A', 'B', 'C'];
$iterator = new ArrayIterator($data);
$iterator->rewind();
while ($iterator->valid()) {
$key = $iterator->key();
$value = $iterator->current();
echo "{$key} => {$value}", PHP_EOL;
$iterator->next();
}
Looping the Loop with SPL
Iterators
What is an Iterator?
0 => A
1 => B
2 => C
Looping the Loop with SPL
Iterators
Looping the Loop with SPL
Iterators
The Iterable Tree
iterable
array
Traversable
Iterator
Generator
IteratorAggregate
Looping the Loop with SPL
Iterators
The Iterable Tree
Not all iterables are equal
You can count the elements in an array !
Can you count the elements in an Iterator?
Looping the Loop with SPL
Iterators
The Iterable Tree
Not all iterables are equal
You can access the elements of an array by
their index !
Can you access the elements of an Iterator
by index ?
Looping the Loop with SPL
Iterators
The Iterable Tree
Not all iterables are equal
You can rewind an Iterator !
Can you rewind a Generator ?
Looping the Loop with SPL
Iterators
The Iterable Tree
Not all iterables are equal
Iterator_* functions (e.g. iterator_to_array)
work on Iterators ?
Can you use iterator_* functions on an
IteratorAggregate ?
Looping the Loop with SPL
Iterators
The Iterable Tree
iterable
array
Traversable
Iterator
Generator
IteratorAggregate
Iterable is a pseudo-type
introduced in PHP 7.1. It accepts
any array, or any object that
implements the Traversable
interface. Both of these types are
iterable using foreach.
Looping the Loop with SPL
Iterators
The Iterable Tree
iterable
array
Traversable
Iterator
Generator
IteratorAggregate
An array in PHP is an ordered map, a
type that associates values to keys. This
type is optimized for several different
uses; it can be treated as an array, list
(vector), hash table (an implementation
of a map), dictionary, collection, stack,
queue, and more.
The foreach control structure exists
specifically for arrays.
Looping the Loop with SPL
Iterators
The Iterable Tree
iterable
array
Traversable
Iterator
Generator
IteratorAggregate
Abstract base interface to detect if a
class is traversable using foreach. It
cannot be implemented alone in
Userland code; but instead must be
implemented through either
IteratorAggregate or Iterator.
Internal (built-in) classes that implement
this interface can be used in a foreach
construct and do not need to implement
IteratorAggregate or Iterator.
Looping the Loop with SPL
Iterators
The Iterable Tree
iterable
array
Traversable
Iterator
Generator
IteratorAggregate
Abstract base interface to detect if a
class is traversable using foreach. It
cannot be implemented alone in
Userland code; but instead must be
implemented through either
IteratorAggregate or Iterator.
PDOStatement
DatePeriod
SimpleXMLElement
Looping the Loop with SPL
Iterators
The Iterable Tree
iterable
array
Traversable
Iterator
Generator
IteratorAggregate
An Interface for external iterators or
objects that can be iterated themselves
internally.
PHP already provides a number of
iterators for many day to day tasks
within the Standard PHP Library (SPL).
SPL Iterators
SPL DataStructures
WeakMaps (PHP 8)
Looping the Loop with SPL
Iterators
The Iterable Tree
iterable
array
Traversable
Iterator
Generator
IteratorAggregate
Generators provide an easy way to
implement simple user-defined iterators
without the overhead or complexity of
implementing a class that implements
the Iterator interface.
This flexibility does come at a cost,
however: generators are forward-only
iterators, and cannot be rewound once
iteration has started.
Looping the Loop with SPL
Iterators
The Iterable Tree
iterable
array
Traversable
Iterator
Generator
IteratorAggregate
IteratorAggregate is a special interface
for implementing an abstraction layer
between user code and iterators.
Implementing an IteratorAggregate will
allow you to delegate the work of
iteration to a separate class, while still
enabling you to use the collection inside
a foreach loop.
Looping the Loop with SPL
Iterators
Looping the Loop with SPL
Iterators
Implementing an Iterator
interface Iterator extends Traversable {
/* Methods */
abstract public current ( void ) : mixed
abstract public key ( void ) : scalar
abstract public next ( void ) : void
abstract public rewind ( void ) : void
abstract public valid ( void ) : bool
}
Looping the Loop with SPL
Iterators
Implementing an Iterator
class Utf8StringIterator implements Iterator {
private $string;
private $offset = 0;
private $length = 0;
public function __construct(string $string) {
$this->string = $string;
$this->length = iconv_strlen($string);
}
public function valid(): bool {
return $this->offset < $this->length;
}
...
}
Looping the Loop with SPL
Iterators
Implementing an Iterator
class Utf8StringIterator implements Iterator {
...
public function rewind(): void {
$this->offset = 0;
}
public function current(): string {
return iconv_substr($this->string, $this->offset, 1);
}
public function key(): int {
return $this->offset;
}
public function next(): void {
++$this->offset;
}
}
Looping the Loop with SPL
Iterators
Implementing an Iterator
$stringIterator = new Utf8StringIterator('Καλησπέρα σε όλους');
foreach($stringIterator as $character) {
echo "[{$character}]";
}
Looping the Loop with SPL
Iterators
Implementing an Iterator
[Κ][α][λ][η][σ][π][έ][ρ][α][ ][σ][ε][ ][ό][λ][ο][υ][ς]
Looping the Loop with SPL
Iterators
Implementing an Iterator
class FileLineIterator implements Iterator {
private $fileHandle;
private $line = 1;
public function __construct(string $fileName) {
$this->fileHandle = fopen($fileName, 'r');
}
public function __destruct() {
fclose($this->fileHandle);
}
}
Looping the Loop with SPL
Iterators
Implementing an Iterator
class FileLineIterator implements Iterator {
...
public function current(): string {
$fileData = fgets($this->fileHandle);
return rtrim($fileData, "n");
}
public function key(): int {
return $this->line;
}
public function next(): void {
++$this->line;
}
}
Looping the Loop with SPL
Iterators
Implementing an Iterator
class FileLineIterator implements Iterator {
...
public function rewind(): void {
fseek($this->fileHandle, 0);
$this->line = 1;
}
public function valid(): bool {
return !feof($this->fileHandle);
}
}
Looping the Loop with SPL
Iterators
Implementing an Iterator
$fileLineIterator = new FileLineIterator(__FILE__);
foreach($fileLineIterator as $lineNumber => $fileLine) {
echo "{$lineNumber}: {$fileLine}", PHP_EOL;
}
Looping the Loop with SPL
Iterators
Implementing an Iterator
1: <?php
2:
3: class FileLineIterator implements Iterator {
4: private $fileHandle;
5: private $line = 1;
6:
7: public function __construct(string $fileName) {
8: $this->fileHandle = fopen($fileName, 'r’);
9: }
10:
…
Looping the Loop with SPL
Iterators
Looping the Loop with SPL
Iterators
class UserRepository {
// ...
public function all(): array {
$userQuery = 'SELECT * FROM `users` ...';
$statement = $this->pdo->prepare($userQuery);
$statement->execute();
$users = $statement->fetchAll();
return array_map(fn(array $user): User => User::fromArray($user), $users);
}
}
Looping the Loop with SPL
Iterators
class UserRepository {
// ...
/**
* @return User[]
*/
public function all(): array {
$userQuery = 'SELECT * FROM `users` ...';
$statement = $this->pdo->prepare($userQuery);
$statement->execute();
$users = $statement->fetchAll();
return array_map(fn(array $user): User => User::fromArray($user), $users);
}
}
Looping the Loop with SPL
Iterators
class UserCollection extends ArrayIterator {
}
Looping the Loop with SPL
Iterators
class UserRepository {
// ...
public function all(): UserCollection {
$userQuery = 'SELECT * FROM `users` ...';
$statement = $this->pdo->prepare($userQuery);
$statement->execute();
$users = $statement->fetchAll();
return new UserCollection(
array_map(fn(array $user): User => User::fromArray($user), $users)
);
}
}
Looping the Loop with SPL
Iterators
class UserCollection extends ArrayIterator {
public function current(): User {
return User::fromArray(parent::current());
}
}
Looping the Loop with SPL
Iterators
class UserRepository {
// ...
public function all(): UserCollection {
$userQuery = 'SELECT * FROM `users` ...';
$statement = $this->pdo->prepare($userQuery);
$statement->execute();
$users = $statement->fetchAll();
return new UserCollection($users);
}
}
Looping the Loop with SPL
Iterators
Looping the Loop with SPL
Iterators
ArrayIterator
Implements:
Countable
ArrayAccess
Serializable
SeekableIterator (which entends Iterator)
Looping the Loop with SPL
Iterators
ArrayIterator
Implements:
Countable
Looping the Loop with SPL
Iterators
ArrayIterator – Countable
interface Countable {
/* Methods */
abstract public count ( void ) : int
}
Looping the Loop with SPL
Iterators
ArrayIterator – Countable
$userData = ['user1', 'user2', 'user3', 'user4'];
$userList = new UserList($userData);
$userCount = count($userList);
echo "There are {$userCount} users in this list", PHP_EOL;
Looping the Loop with SPL
Iterators
ArrayIterator – Countable
$userData = ['user1', 'user2', 'user3', 'user4'];
$userList = new UserList($userData);
echo "There are {$userList->count()} users in this list", PHP_EOL;
Looping the Loop with SPL
Iterators
ArrayIterator – Countable
There are 4 users in this list
Looping the Loop with SPL
Iterators
ArrayIterator
Implements:
Countable
ArrayAccess
Looping the Loop with SPL
Iterators
ArrayIterator – ArrayAccess
interface ArrayAccess {
/* Methods */
abstract public offsetExists ( mixed $offset ) : bool
abstract public offsetGet ( mixed $offset ) : mixed
abstract public offsetSet ( mixed $offset , mixed $value ) : void
abstract public offsetUnset ( mixed $offset ) : void
}
Looping the Loop with SPL
Iterators
ArrayIterator – ArrayAccess
$userData = ['user1', 'user2', 'user3', 'user4'];
$userList = new UserList($userData);
echo "The 3rd entry in the list is {$userList[2]}", PHP_EOL;
Looping the Loop with SPL
Iterators
ArrayIterator – ArrayAccess
The 3rd entry in the list is user3
Looping the Loop with SPL
Iterators
ArrayIterator
Implements:
Countable
ArrayAccess
Serializable
Looping the Loop with SPL
Iterators
ArrayIterator – Serializable
interface Serializable {
/* Methods */
abstract public serialize ( void ) : string
abstract public unserialize ( string $serialized ) : void
}
Looping the Loop with SPL
Iterators
ArrayIterator – Serializable
$userData = ['user1', 'user2', 'user3', 'user4'];
$userList = new UserList($userData);
var_dump(serialize($userList));
Looping the Loop with SPL
Iterators
ArrayIterator – Serializable
string(117)
"O:8:"UserList":4:{i:0;i:0;i:1;a:4:{i:0;s:5:"user1";
i:1;s:5:"user2";i:2;s:5:"user3";i:3;s:5:"user4";}i:2;
a:0:{}i:3;N;}"
Looping the Loop with SPL
Iterators
ArrayIterator
Implements:
Countable
ArrayAccess
Serializable
SeekableIterator (which entends Iterator)
Looping the Loop with SPL
Iterators
ArrayIterator – SeekableIterator
SeekableIterator extends Iterator {
/* Methods */
abstract public seek ( int $position ) : void
/* Inherited methods */
abstract public Iterator::current ( void ) : mixed
abstract public Iterator::key ( void ) : scalar
abstract public Iterator::next ( void ) : void
abstract public Iterator::rewind ( void ) : void
abstract public Iterator::valid ( void ) : bool
}
Looping the Loop with SPL
Iterators
ArrayIterator – SeekableIterator
$userData = ['user1', 'user2', 'user3', 'user4'];
$userList = new UserList($userData);
$userList->seek(2);
while ($userList->valid()) {
echo $userList->current(), PHP_EOL;
$userList->next();
}
Looping the Loop with SPL
Iterators
ArrayIterator – SeekableIterator
user3
user4
Looping the Loop with SPL
Iterators
ArrayIterator – SeekableIterator
$userData = ['user1', 'user2', 'user3', 'user4'];
$userList = new UserList($userData);
$userList->seek(2);
foreach($userList as $userName) {
echo $userName, PHP_EOL;
}
Looping the Loop with SPL
Iterators
ArrayIterator – SeekableIterator
user1
user2
user3
user4

Looping the Loop with SPL
Iterators
ArrayIterator – SeekableIterator
$userData = ['A' => 'user1', 'B' => 'user2', 'C' => 'user3', 'D' => 'user4'];
$userList = new UserList($userData);
$userList->seek('C');
while ($userList->valid()) {
echo $userList->current(), PHP_EOL;
$userList->next();
}
Looping the Loop with SPL
Iterators
ArrayIterator – SeekableIterator
PHP7
Warning:
ArrayIterator::seek() expects parameter 1 to be int,
string given

Looping the Loop with SPL
Iterators
ArrayIterator – SeekableIterator
PHP8
Fatal error: Uncaught TypeError
ArrayIterator::seek(): Argument #1 ($position) must be
of type int, string given

Looping the Loop with SPL
Iterators
ArrayIterator
Implements:
Countable
ArrayAccess
Serializable
SeekableIterator (which entends Iterator)
Also provides methods for sorting
Doesn’t work with array_* functions
Looping the Loop with SPL
Iterators
Looping the Loop with SPL
Iterators
Looping the Loop with SPL
Iterators
LimitIterator
$userData = ['user1', 'user2', 'user3', 'user4'];
$userList = new LimitIterator(
new UserList($userData),
2,
1
);
foreach($userList as $value) {
echo $value, PHP_EOL;
}
Looping the Loop with SPL
Iterators
LimitIterator
user3
Looping the Loop with SPL
Iterators
InfiniteIterator
$weekdayNames = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'];
$todayOffset = (int) (new DateTime('2020-09-08'))->format('w');
$weekdayList = new LimitIterator(
new InfiniteIterator( new ArrayIterator($weekdayNames) ),
$todayOffset,
14
);
foreach($weekdayList as $dayOfWeek) {
echo $dayOfWeek, PHP_EOL;
}
Looping the Loop with SPL
Iterators
InfiniteIterator
Tues
Wed
Thurs
Fri
Sat
Sun
Mon
Tues
Wed
Thurs
Fri
Sat
Sun
Mon
Looping the Loop with SPL
Iterators
CallbackFilterIterator
$weekdayNames = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'];
$todayOffset = (int) (new DateTime('2020-09-15'))->format('w');
$workdayList = new CallbackFilterIterator(
new LimitIterator(
new InfiniteIterator( new ArrayIterator($weekdayNames) ),
$todayOffset,
14
),
fn($dayName): bool => $dayName !== 'Sat' && $dayName !== 'Sun'
);
foreach($workdayList as $dayOfWeek) {
echo $dayOfWeek, PHP_EOL;
}
Looping the Loop with SPL
Iterators
CallbackFilterIterator
Tues
Wed
Thurs
Fri
Mon
Tues
Wed
Thurs
Fri
Mon
Looping the Loop with SPL
Iterators
Looping the Loop with SPL
Iterators
FilterIterator
abstract FilterIterator extends IteratorIterator implements OuterIterator {
/* Methods */
public abstract accept ( void ) : bool
public __construct ( Iterator $iterator )
public current ( void ) : mixed
public getInnerIterator ( void ) : Iterator
public key ( void ) : mixed
public next ( void ) : void
public rewind ( void ) : void
public valid ( void ) : bool
}
Looping the Loop with SPL
Iterators
FilterIterator
class ImageFileIterator extends FilterIterator {
// Overwrite the constructor to automagically create an inner iterator
// to iterate the file system when given a path name.
public function __construct(string $path) {
parent::__construct(new FilesystemIterator($path));
}
// Overwrite the accept method to perform a super simple test to
// determine if the files found were images or not.
public function accept(): bool {
$fileObject = $this->getInnerIterator()->current();
return preg_match('/^(?:gif|jpe?g|png)$/i', $fileObject->getExtension());
}
}
Looping the Loop with SPL
Iterators
FilterIterator
class ImageFileIterator extends FilterIterator {
// Overwrite the constructor to automagically create an inner iterator
// to iterate the file system when given a path name.
public function __construct(string $path) {
parent::__construct(new FilesystemIterator($path));
}
// Overwrite the accept method to perform a super simple test to
// determine if the files found were images or not.
public function accept(): bool {
return preg_match('/^(?:gif|jpe?g|png)$/i', $this->getExtension());
}
}
Looping the Loop with SPL
Iterators
FilterIterator
$path = dirname(__FILE__);
foreach(new ImageFileIterator($path) as $imageObject) {
echo $imageObject->getBaseName(), PHP_EOL;
}
Looping the Loop with SPL
Iterators
FilterIterator
anubis.jpg
Carpet.jpg
Crazy Newspaper Headlines.jpg
elephpant.jpg
Pie Chart.jpg
PowerOfBooks.jpg
Struggling-Team.png
TeddyBears.jpg
Looping the Loop with SPL
Iterators
Iterator Keys
class ImageFileIterator extends FilterIterator {
...
// Overwrite the key method to return the file extension as the key
public function key(): string {
return $this->getExtension();
}
}
foreach(new ImageFileIterator($path) as $extension => $imageObject) {
echo "{$extension} => {$imageObject->getBaseName()}", PHP_EOL;
}
Looping the Loop with SPL
Iterators
Iterator Keys
jpg => anubis.jpg
jpg => Carpet.jpg
jpg => Crazy Newspaper Headlines.jpg
jpg => elephpant.jpg
jpg => Pie Chart.jpg
jpg => PowerOfBooks.jpg
png => Struggling-Team.png
jpg => TeddyBears.jpg
Looping the Loop with SPL
Iterators
Iterator Keys
class ImageFileIterator extends FilterIterator {
...
// Overwrite the key method to return the last modified date/time as the key
public function key(): DateTime {
return DateTime::createFromFormat('U', $this->getMTime());
}
}
foreach(new ImageFileIterator($path) as $date => $imageObject) {
echo "{$date->format('Y-m-d H:i:s')} => {$imageObject->getBaseName()}",
PHP_EOL;
}
Looping the Loop with SPL
Iterators
Iterator Keys
2012-03-24 00:38:24 => anubis.jpg
2013-01-27 22:32:20 => Carpet.jpg
2013-03-07 12:16:24 => Crazy Newspaper Headlines.jpg
2012-02-16 22:31:56 => elephpant.jpg
2012-10-09 11:51:56 => Pie Chart.jpg
2012-07-17 12:22:32 => PowerOfBooks.jpg
2012-12-30 18:14:24 => Struggling-Team.png
2012-01-31 11:17:32 => TeddyBears.jpg
Looping the Loop with SPL
Iterators
Looping the Loop with SPL
Iterators
MultipleIterator
$dates = ['Q1-2019', 'Q2-2019', 'Q3-2019', 'Q4-2019'];
$budget = [1200, 1300, 1400, 1500];
$expenditure = [1250, 1315, 1440, 1485];
$budgetElements = count($budget);
for ($i = 0; $i < $budgetElements; $i++) {
echo "{$dates[$i]} - {$budget[$i]}, {$expenditure[$i]}", PHP_EOL;
}
Looping the Loop with SPL
Iterators
MultipleIterator
$dates = ['Q1-2019', 'Q2-2019', 'Q3-2019', 'Q4-2019'];
$budget = [1200, 1300, 1400, 1500];
$expenditure = [1250, 1315, 1440, 1485];
foreach($dates as $key => $period) {
echo "{$period} - {$budget[$key]}, {$expenditure[$key]}", PHP_EOL;
}
Looping the Loop with SPL
Iterators
MultipleIterator
Q1-2019 - 1200, 1250
Q2-2019 - 1300, 1315
Q3-2019 - 1400, 1440
Q4-2019 - 1500, 1485
Looping the Loop with SPL
Iterators
MultipleIterator
function wrapArrayAsIterator(array $array) {
return new ArrayIterator($array);
}
$combinedIterable = new MultipleIterator(MultipleIterator::MIT_KEYS_ASSOC);
$combinedIterable->attachIterator(wrapArrayAsIterator($dates), 'date');
$combinedIterable->attachIterator(wrapArrayAsIterator($budget), 'budget');
$combinedIterable->attachIterator(wrapArrayAsIterator($expenditure), 'expenditure');
Looping the Loop with SPL
Iterators
MultipleIterator
foreach($combinedIterable as $dateValues) {
echo $dateValues['date'],
" - {$dateValues['budget']}, {$dateValues['expenditure']}",
PHP_EOL;
}
Looping the Loop with SPL
Iterators
MultipleIterator
foreach($combinedIterable as $dateValues) {
[$date, $budget, $expenditure] = $dateValues;
echo "{$date} - {$budget}, {$expenditure}", PHP_EOL;
}
Looping the Loop with SPL
Iterators
MultipleIterator
Q1-2019 - 1200, 1250
Q2-2019 - 1300, 1315
Q3-2019 - 1400, 1440
Q4-2019 - 1500, 1485
Looping the Loop with SPL
Iterators
MultipleIterator
function wrapArrayAsIterator(array $array) {
return new ArrayIterator($array);
}
$combinedIterable = new MultipleIterator(MultipleIterator::MIT_KEYS_ASSOC);
$combinedIterable->attachIterator(wrapArrayAsIterator($dates), 'date');
$combinedIterable->attachIterator(wrapArrayAsIterator($budget), 'budget');
$combinedIterable->attachIterator(wrapArrayAsIterator($expenditure), 'expenditure');
Looping the Loop with SPL
Iterators
MultipleIterator
foreach($combinedIterable as $dateValues) {
extract($dateValues);
echo "{$date} - {$budget}, {$expenditure}", PHP_EOL;
}
Looping the Loop with SPL
Iterators
MultipleIterator
Q1-2019 - 1200, 1250
Q2-2019 - 1300, 1315
Q3-2019 - 1400, 1440
Q4-2019 - 1500, 1485
Looping the Loop with SPL
Iterators
MultipleIterator
$allocations = $totalAdvance->allocateTo(count($cars));
foreach ($cars as $i => $car) {
$car->setAdvance($allocations[$i]);
}
Looping the Loop with SPL
Iterators
MultipleIterator
$allocations = $totalAdvance->allocateTo(count($cars));
$advanceAllocations = new MultipleIterator(MultipleIterator::MIT_KEYS_ASSOC);
$advanceAllocations->attachIterator(ArrayIterator($cars), 'car');
$advanceAllocations->attachIterator(ArrayIterator($allocations), 'advance');
foreach($advanceAllocations as $advanceAllocation) {
extract($advanceAllocation);
$car->setAdvance($advance);
}
Looping the Loop with SPL
Iterators
Looping the Loop with SPL
Iterators
Inner and Outer Iterators
Inner Iterator
Implements Iterator, or extends a class that
implements Iterator
ArrayIterator
SeekableIterator
FilesystemIterator
MultipleIterator
Looping the Loop with SPL
Iterators
Inner and Outer Iterators
Outer Iterator
Implements OuterIterator, or extends an
Iterator that already implements
OuterIterator
LimitIterator
InfiniteIterator
FilterIterator
CallbackFilterIterator
Looping the Loop with SPL
Iterators
Recursive Iterators
A RecursiveIterator defines methods to
allow iteration over hierarchical data
structures.
Nested Arrays (and Objects if using
ArrayAccess)
Filesystem Directories/Folders
Looping the Loop with SPL
Iterators
Looping the Loop with SPL
Iterators
class UserRepository {
// ...
public function all(): UserCollection {
$userQuery = 'SELECT * FROM `users` ...';
$statement = $this->pdo->prepare($userQuery);
$statement->execute();
$users = $statement->fetchAll();
return new UserCollection(
array_map(fn(array $user): User => User::fromArray($user), $users)
);
}
}
Looping the Loop with SPL
Iterators
class UserRepository {
// ...
public function all(): Generator {
$userQuery = 'SELECT * FROM `users` ...';
$statement = $this->pdo->prepare($userQuery);
$statement->execute();
while ($user = $statement->fetch()) {
yield User::fromArray($user);
}
}
}
Looping the Loop with SPL
Iterators
class UserRepository {
// ...
/**
* @return Generator|User[]
*/
public function all(): Generator {
$userQuery = 'SELECT * FROM `users` ...';
$statement = $this->pdo->prepare($userQuery);
$statement->execute();
while ($user = $statement->fetch()) {
yield User::fromArray($user);
}
}
}
Looping the Loop with SPL
Iterators
IteratorAggregate
IteratorAggregate extends Traversable {
/* Methods */
abstract public getIterator ( void ) : Traversable
}
Looping the Loop with SPL
Iterators
class UserCollection implements IteratorAggregate {
private PDOStatement $pdoStatement;
public function __construct(PDOStatement $pdoStatement) {
$this->pdoStatement = $pdoStatement;
}
public function getIterator(): Traversable {
$this->pdoStatement->execute();
while ($user = $this->pdoStatement->fetch()) {
yield User::fromArray($user);
}
}
}
Looping the Loop with SPL
Iterators
class UserRepository {
// ...
public function all(): UserCollection {
$userQuery = 'SELECT * FROM `users` ...';
$statement = $this->pdo->prepare($userQuery);
return new UserCollection($statement);
}
}
Looping the Loop with SPL
Iterators
Implementing a Fluent Nested Iterator
$weekdayNames = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'];
$todayOffset = (int) (new DateTime('2020-09-15'))->format('w');
$workdayList = new CallbackFilterIterator(
new LimitIterator(
new InfiniteIterator( new ArrayIterator($weekdayNames) ),
$todayOffset,
14
),
fn($dayName): bool => $dayName !== 'Sat' && $dayName !== 'Sun'
);
foreach($workdayList as $dayOfWeek) {
echo $dayOfWeek, PHP_EOL;
}
Looping the Loop with SPL
Iterators
Implementing a Fluent Nested Iterator
class FluentNestedIterator implements IteratorAggregate {
protected iterable $iterator;
public function __construct(iterable $iterator) {
$this->iterator = $iterator;
}
public function with(string $iterable, ...$args): self {
$this->iterator = new $iterable($this->iterator, ...$args);
return $this;
}
public function getIterator() {
return $this->iterator;
}
}
Looping the Loop with SPL
Iterators
Implementing a Fluent Nested Iterator
$weekdayNames = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat'];
$todayOffset = (int) (new DateTime('2020-10-08'))->format('w');
$workdayList = (new FluentNestedIterator(new ArrayIterator($weekdayNames)))
->with(InfiniteIterator::class)
->with(LimitIterator::class, $todayOffset, 14)
->with(
CallbackFilterIterator::class,
fn($dayName): bool => $dayName !== 'Sat' && $dayName !== 'Sun'
);
foreach($workdayList as $dayOfWeek) {
echo $dayOfWeek, PHP_EOL;
}
Looping the Loop with SPL
Iterators
Implementing a Fluent Nested Iterator
Thurs
Fri
Mon
Tues
Wed
Thurs
Fri
Mon
Tues
Wed
Looping the Loop with SPL
Iterators
Looping the Loop with SPL
Iterators
Array Functions
Don’t work with Traversables
Looping the Loop with SPL
Iterators
Array Functions
Don’t work with Traversables
Looping the Loop with SPL
Iterators
Array Functions – Filter
function filter(iterable $iterator, Callable $callback = null) {
if ($callback === null) {
$callback = 'iterableFilterNotEmpty';
}
foreach ($iterator as $key => $value) {
if ($callback($value)) {
yield $key => $value;
}
}
}
Looping the Loop with SPL
Iterators
Array Functions – Filter
$startTime = new DateTime('2015-11-23 13:20:00Z');
$endTime = new DateTime('2015-11-23 13:30:00Z');
$timeFilter = function($timestamp) use ($startTime, $endTime) {
return $timestamp >= $startTime && $timestamp <= $endTime;
};
$filteredTrackingData = filter(
$gpxReader->getElements('trkpt'),
$timeFilter,
ARRAY_FILTER_USE_KEY
);
foreach ($filteredTrackingData as $time => $element) {
...
}
Looping the Loop with SPL
Iterators
Array Functions – Filter
2015-11-23 13:24:40
latitude: 53.5441 longitude: -2.7416 elevation: 124
2015-11-23 13:24:49
latitude: 53.5441 longitude: -2.7416 elevation: 122
2015-11-23 13:24:59
latitude: 53.5441 longitude: -2.7416 elevation: 120
2015-11-23 13:25:09
latitude: 53.5441 longitude: -2.7417 elevation: 120
2015-11-23 13:25:19
latitude: 53.5441 longitude: -2.7417 elevation: 121
2015-11-23 13:25:29
latitude: 53.5441 longitude: -2.7417 elevation: 120
2015-11-23 13:25:39
latitude: 53.5441 longitude: -2.7417 elevation: 120
Looping the Loop with SPL
Iterators
Array Functions – Filter
Of course, we could always use a
CallBackFilterIterator
Looping the Loop with SPL
Iterators
Array Functions – Map
function map(Callable $callback, iterable $iterator) {
foreach ($iterator as $key => $value) {
yield $key => $callback($value);
}
}
Looping the Loop with SPL
Iterators
Array Functions – Map
$distanceCalculator = new GpxReaderHelpersDistanceCalculator();
$mappedTrackingData = map(
[$distanceCalculator, 'setDistanceProperty'],
$gpxReader->getElements('trkpt')
);
foreach ($mappedTrackingData as $time => $element) {
...
}
Looping the Loop with SPL
Iterators
Array Functions – Map
2015-11-23 14:57:07
latitude: 53.5437 longitude: -2.7424 elevation: 103
distance from previous point: 6.93 m
2015-11-23 14:57:17
latitude: 53.5437 longitude: -2.7424 elevation: 100
distance from previous point: 1.78 m
2015-11-23 14:57:27
latitude: 53.5438 longitude: -2.7425 elevation: 89
distance from previous point: 11.21 m
2015-11-23 14:57:37
latitude: 53.5439 longitude: -2.7424 elevation: 83
distance from previous point: 9.23 m
2015-11-23 14:57:47
latitude: 53.5439 longitude: -2.7425 elevation: 92
distance from previous point: 5.40 m
Looping the Loop with SPL
Iterators
Array Functions – Walk
iterator_apply()
iterator_apply(
Traversable $iterator,
Callable $callback
[, array $args = NULL ]
) : int
Looping the Loop with SPL
Iterators
Array Functions – Reduce
function reduce(iterable $iterator, Callable $callback, $initial = null) {
$result = $initial;
foreach($iterator as $value) {
$result = $callback($result, $value);
}
return $result;
}
Looping the Loop with SPL
Iterators
Array Functions – Reduce
$distanceCalculator = new GpxReaderHelpersDistanceCalculator();
$totalDistance = reduce(
map(
[$distanceCalculator, 'setDistanceProperty'],
$gpxReader->getElements('trkpt')
),
function($runningTotal, $value) {
return $runningTotal + $value->distance;
},
0.0
);
Looping the Loop with SPL
Iterators
Array Functions – Reduce
Total distance travelled is 4.33 km
Looping the Loop with SPL
Iterators
Array Functions – Other Iterator
Functions
Iterator_count()
iterator_count ( Traversable $iterator ) : int
Looping the Loop with SPL
Iterators
Array Functions – Other Iterator
Functions
Iterator_to_array()
iterator_to_array (
Traversable $iterator
[, bool $use_keys = TRUE ]
) : array
Looping the Loop with SPL
Iterators
Looping the Loop with SPL
Iterators
A Functional Guide to Cat Herding with PHP
Generators
• https://markbakeruk.net/2016/01/19/a-functional-guide-to-cat-herding-with-php-generators/
• https://markbakeruk.net/2020/01/05/filtering-and-mapping-with-spl-iterators/
• https://markbakeruk.net/2019/12/31/parallel-looping-in-php-with-spls-multipleiterator/
Looping the Loop with SPL
Iterators
Iterating PHP Iterators
By Cal Evans
https://leanpub.com/iteratingphpiterators
by Joshua Thijssen
https://www.phparch.com/books/mastering-the-spl-library/
Who am I?
Mark Baker
Most Recently: Senior Software Engineer
MessageBird BV, Amsterdam
Coordinator and Developer of:
Open Source PHPOffice library
PHPExcel, PHPWord, PHPPowerPoint, PHPProject, PHPVisio
Minor contributor to PHP core (SPL DataStructures)
Other small open source libraries available on github
@Mark_Baker
https://github.com/MarkBaker
http://uk.linkedin.com/pub/mark-baker/b/572/171
http://markbakeruk.net
Looping the
Loop
with
SPL Iterators

Weitere ähnliche Inhalte

Was ist angesagt?

Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meetMario Fusco
 
OOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerOOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerMario Fusco
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongMario Fusco
 
SPL to the Rescue - Tek 09
SPL to the Rescue - Tek 09SPL to the Rescue - Tek 09
SPL to the Rescue - Tek 09Elizabeth Smith
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modelingMario Fusco
 
OpenGurukul : Language : PHP
OpenGurukul : Language : PHPOpenGurukul : Language : PHP
OpenGurukul : Language : PHPOpen Gurukul
 
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STMConcurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STMMario Fusco
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Mario Fusco
 
Creating Lazy stream in CSharp
Creating Lazy stream in CSharpCreating Lazy stream in CSharp
Creating Lazy stream in CSharpDhaval Dalal
 
Spl to the Rescue - Zendcon 09
Spl to the Rescue - Zendcon 09Spl to the Rescue - Zendcon 09
Spl to the Rescue - Zendcon 09Elizabeth Smith
 
Elegant Solutions for Everyday Python Problems Pycon 2018 - Nina Zakharenko
Elegant Solutions for Everyday Python Problems Pycon 2018 - Nina ZakharenkoElegant Solutions for Everyday Python Problems Pycon 2018 - Nina Zakharenko
Elegant Solutions for Everyday Python Problems Pycon 2018 - Nina ZakharenkoNina Zakharenko
 
Elegant Solutions For Everyday Python Problems - PyCon Canada 2017
Elegant Solutions For Everyday Python Problems - PyCon Canada 2017Elegant Solutions For Everyday Python Problems - PyCon Canada 2017
Elegant Solutions For Everyday Python Problems - PyCon Canada 2017Nina Zakharenko
 
Clojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMClojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMsunng87
 
(map Clojure everyday-tasks)
(map Clojure everyday-tasks)(map Clojure everyday-tasks)
(map Clojure everyday-tasks)Jacek Laskowski
 
ekb.py - Python VS ...
ekb.py - Python VS ...ekb.py - Python VS ...
ekb.py - Python VS ...it-people
 

Was ist angesagt? (20)

Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meet
 
OOP and FP - Become a Better Programmer
OOP and FP - Become a Better ProgrammerOOP and FP - Become a Better Programmer
OOP and FP - Become a Better Programmer
 
If You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are WrongIf You Think You Can Stay Away from Functional Programming, You Are Wrong
If You Think You Can Stay Away from Functional Programming, You Are Wrong
 
Subroutines
SubroutinesSubroutines
Subroutines
 
SPL to the Rescue - Tek 09
SPL to the Rescue - Tek 09SPL to the Rescue - Tek 09
SPL to the Rescue - Tek 09
 
From object oriented to functional domain modeling
From object oriented to functional domain modelingFrom object oriented to functional domain modeling
From object oriented to functional domain modeling
 
OpenGurukul : Language : PHP
OpenGurukul : Language : PHPOpenGurukul : Language : PHP
OpenGurukul : Language : PHP
 
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STMConcurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...Laziness, trampolines, monoids and other functional amenities: this is not yo...
Laziness, trampolines, monoids and other functional amenities: this is not yo...
 
Advanced Python : Decorators
Advanced Python : DecoratorsAdvanced Python : Decorators
Advanced Python : Decorators
 
Creating Lazy stream in CSharp
Creating Lazy stream in CSharpCreating Lazy stream in CSharp
Creating Lazy stream in CSharp
 
Spl to the Rescue - Zendcon 09
Spl to the Rescue - Zendcon 09Spl to the Rescue - Zendcon 09
Spl to the Rescue - Zendcon 09
 
Perl
PerlPerl
Perl
 
Elegant Solutions for Everyday Python Problems Pycon 2018 - Nina Zakharenko
Elegant Solutions for Everyday Python Problems Pycon 2018 - Nina ZakharenkoElegant Solutions for Everyday Python Problems Pycon 2018 - Nina Zakharenko
Elegant Solutions for Everyday Python Problems Pycon 2018 - Nina Zakharenko
 
Elegant Solutions For Everyday Python Problems - PyCon Canada 2017
Elegant Solutions For Everyday Python Problems - PyCon Canada 2017Elegant Solutions For Everyday Python Problems - PyCon Canada 2017
Elegant Solutions For Everyday Python Problems - PyCon Canada 2017
 
Clojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVMClojure: Practical functional approach on JVM
Clojure: Practical functional approach on JVM
 
(map Clojure everyday-tasks)
(map Clojure everyday-tasks)(map Clojure everyday-tasks)
(map Clojure everyday-tasks)
 
Python programming
Python  programmingPython  programming
Python programming
 
Don't do this
Don't do thisDon't do this
Don't do this
 
ekb.py - Python VS ...
ekb.py - Python VS ...ekb.py - Python VS ...
ekb.py - Python VS ...
 

Ähnlich wie Looping the Loop with SPL Iterators

Looping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsLooping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsMark Baker
 
Looping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsLooping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsMark Baker
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Developmentjsmith92
 
Scala is java8.next()
Scala is java8.next()Scala is java8.next()
Scala is java8.next()daewon jeong
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest UpdatesIftekhar Eather
 
Introduction to new features in java 8
Introduction to new features in java 8Introduction to new features in java 8
Introduction to new features in java 8Raffi Khatchadourian
 
What is new in java 8 concurrency
What is new in java 8 concurrencyWhat is new in java 8 concurrency
What is new in java 8 concurrencykshanth2101
 
SOLID mit Java 8
SOLID mit Java 8SOLID mit Java 8
SOLID mit Java 8Roland Mast
 
Clojure - A new Lisp
Clojure - A new LispClojure - A new Lisp
Clojure - A new Lispelliando dias
 
Using spl tools in your code
Using spl tools in your codeUsing spl tools in your code
Using spl tools in your codeElizabeth Smith
 
Class 3 - PHP Functions
Class 3 - PHP FunctionsClass 3 - PHP Functions
Class 3 - PHP FunctionsAhmed Swilam
 
Java 8 - Lambdas and much more
Java 8 - Lambdas and much moreJava 8 - Lambdas and much more
Java 8 - Lambdas and much moreAlin Pandichi
 
PHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generationPHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generationAlexander Obukhov
 
Javascript fundamentals for php developers
Javascript fundamentals for php developersJavascript fundamentals for php developers
Javascript fundamentals for php developersChris Ramakers
 

Ähnlich wie Looping the Loop with SPL Iterators (20)

Looping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsLooping the Loop with SPL Iterators
Looping the Loop with SPL Iterators
 
Looping the Loop with SPL Iterators
Looping the Loop with SPL IteratorsLooping the Loop with SPL Iterators
Looping the Loop with SPL Iterators
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
Scala is java8.next()
Scala is java8.next()Scala is java8.next()
Scala is java8.next()
 
Introducing PHP Latest Updates
Introducing PHP Latest UpdatesIntroducing PHP Latest Updates
Introducing PHP Latest Updates
 
Introduction to new features in java 8
Introduction to new features in java 8Introduction to new features in java 8
Introduction to new features in java 8
 
Introduction to new features in java 8
Introduction to new features in java 8Introduction to new features in java 8
Introduction to new features in java 8
 
What is new in java 8 concurrency
What is new in java 8 concurrencyWhat is new in java 8 concurrency
What is new in java 8 concurrency
 
SOLID mit Java 8
SOLID mit Java 8SOLID mit Java 8
SOLID mit Java 8
 
Clojure - A new Lisp
Clojure - A new LispClojure - A new Lisp
Clojure - A new Lisp
 
Using spl tools in your code
Using spl tools in your codeUsing spl tools in your code
Using spl tools in your code
 
Best practices tekx
Best practices tekxBest practices tekx
Best practices tekx
 
Class 3 - PHP Functions
Class 3 - PHP FunctionsClass 3 - PHP Functions
Class 3 - PHP Functions
 
Spl in the wild
Spl in the wildSpl in the wild
Spl in the wild
 
Java 8 - Lambdas and much more
Java 8 - Lambdas and much moreJava 8 - Lambdas and much more
Java 8 - Lambdas and much more
 
php AND MYSQL _ppt.pdf
php AND MYSQL _ppt.pdfphp AND MYSQL _ppt.pdf
php AND MYSQL _ppt.pdf
 
Php Tutorials for Beginners
Php Tutorials for BeginnersPhp Tutorials for Beginners
Php Tutorials for Beginners
 
PHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generationPHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generation
 
PHP 7
PHP 7PHP 7
PHP 7
 
Javascript fundamentals for php developers
Javascript fundamentals for php developersJavascript fundamentals for php developers
Javascript fundamentals for php developers
 

Mehr von Mark Baker

Deploying Straight to Production
Deploying Straight to ProductionDeploying Straight to Production
Deploying Straight to ProductionMark Baker
 
Deploying Straight to Production
Deploying Straight to ProductionDeploying Straight to Production
Deploying Straight to ProductionMark Baker
 
Deploying Straight to Production
Deploying Straight to ProductionDeploying Straight to Production
Deploying Straight to ProductionMark Baker
 
A Brief History of Elephpants
A Brief History of ElephpantsA Brief History of Elephpants
A Brief History of ElephpantsMark Baker
 
Aspects of love slideshare
Aspects of love slideshareAspects of love slideshare
Aspects of love slideshareMark Baker
 
Does the SPL still have any relevance in the Brave New World of PHP7?
Does the SPL still have any relevance in the Brave New World of PHP7?Does the SPL still have any relevance in the Brave New World of PHP7?
Does the SPL still have any relevance in the Brave New World of PHP7?Mark Baker
 
A Brief History of ElePHPants
A Brief History of ElePHPantsA Brief History of ElePHPants
A Brief History of ElePHPantsMark Baker
 
Coding Horrors
Coding HorrorsCoding Horrors
Coding HorrorsMark Baker
 
Anonymous classes2
Anonymous classes2Anonymous classes2
Anonymous classes2Mark Baker
 
Testing the Untestable
Testing the UntestableTesting the Untestable
Testing the UntestableMark Baker
 
Anonymous Classes: Behind the Mask
Anonymous Classes: Behind the MaskAnonymous Classes: Behind the Mask
Anonymous Classes: Behind the MaskMark Baker
 
Does the SPL still have any relevance in the Brave New World of PHP7?
Does the SPL still have any relevance in the Brave New World of PHP7?Does the SPL still have any relevance in the Brave New World of PHP7?
Does the SPL still have any relevance in the Brave New World of PHP7?Mark Baker
 
Coding Horrors
Coding HorrorsCoding Horrors
Coding HorrorsMark Baker
 
Does the SPL still have any relevance in the Brave New World of PHP7?
Does the SPL still have any relevance in the Brave New World of PHP7?Does the SPL still have any relevance in the Brave New World of PHP7?
Does the SPL still have any relevance in the Brave New World of PHP7?Mark Baker
 
Giving birth to an ElePHPant
Giving birth to an ElePHPantGiving birth to an ElePHPant
Giving birth to an ElePHPantMark Baker
 
A Functional Guide to Cat Herding with PHP Generators
A Functional Guide to Cat Herding with PHP GeneratorsA Functional Guide to Cat Herding with PHP Generators
A Functional Guide to Cat Herding with PHP GeneratorsMark Baker
 
A Functional Guide to Cat Herding with PHP Generators
A Functional Guide to Cat Herding with PHP GeneratorsA Functional Guide to Cat Herding with PHP Generators
A Functional Guide to Cat Herding with PHP GeneratorsMark Baker
 
SPL - The Undiscovered Library - PHPBarcelona 2015
SPL - The Undiscovered Library - PHPBarcelona 2015SPL - The Undiscovered Library - PHPBarcelona 2015
SPL - The Undiscovered Library - PHPBarcelona 2015Mark Baker
 
Zephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensionsZephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensionsMark Baker
 
Flying under the radar
Flying under the radarFlying under the radar
Flying under the radarMark Baker
 

Mehr von Mark Baker (20)

Deploying Straight to Production
Deploying Straight to ProductionDeploying Straight to Production
Deploying Straight to Production
 
Deploying Straight to Production
Deploying Straight to ProductionDeploying Straight to Production
Deploying Straight to Production
 
Deploying Straight to Production
Deploying Straight to ProductionDeploying Straight to Production
Deploying Straight to Production
 
A Brief History of Elephpants
A Brief History of ElephpantsA Brief History of Elephpants
A Brief History of Elephpants
 
Aspects of love slideshare
Aspects of love slideshareAspects of love slideshare
Aspects of love slideshare
 
Does the SPL still have any relevance in the Brave New World of PHP7?
Does the SPL still have any relevance in the Brave New World of PHP7?Does the SPL still have any relevance in the Brave New World of PHP7?
Does the SPL still have any relevance in the Brave New World of PHP7?
 
A Brief History of ElePHPants
A Brief History of ElePHPantsA Brief History of ElePHPants
A Brief History of ElePHPants
 
Coding Horrors
Coding HorrorsCoding Horrors
Coding Horrors
 
Anonymous classes2
Anonymous classes2Anonymous classes2
Anonymous classes2
 
Testing the Untestable
Testing the UntestableTesting the Untestable
Testing the Untestable
 
Anonymous Classes: Behind the Mask
Anonymous Classes: Behind the MaskAnonymous Classes: Behind the Mask
Anonymous Classes: Behind the Mask
 
Does the SPL still have any relevance in the Brave New World of PHP7?
Does the SPL still have any relevance in the Brave New World of PHP7?Does the SPL still have any relevance in the Brave New World of PHP7?
Does the SPL still have any relevance in the Brave New World of PHP7?
 
Coding Horrors
Coding HorrorsCoding Horrors
Coding Horrors
 
Does the SPL still have any relevance in the Brave New World of PHP7?
Does the SPL still have any relevance in the Brave New World of PHP7?Does the SPL still have any relevance in the Brave New World of PHP7?
Does the SPL still have any relevance in the Brave New World of PHP7?
 
Giving birth to an ElePHPant
Giving birth to an ElePHPantGiving birth to an ElePHPant
Giving birth to an ElePHPant
 
A Functional Guide to Cat Herding with PHP Generators
A Functional Guide to Cat Herding with PHP GeneratorsA Functional Guide to Cat Herding with PHP Generators
A Functional Guide to Cat Herding with PHP Generators
 
A Functional Guide to Cat Herding with PHP Generators
A Functional Guide to Cat Herding with PHP GeneratorsA Functional Guide to Cat Herding with PHP Generators
A Functional Guide to Cat Herding with PHP Generators
 
SPL - The Undiscovered Library - PHPBarcelona 2015
SPL - The Undiscovered Library - PHPBarcelona 2015SPL - The Undiscovered Library - PHPBarcelona 2015
SPL - The Undiscovered Library - PHPBarcelona 2015
 
Zephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensionsZephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensions
 
Flying under the radar
Flying under the radarFlying under the radar
Flying under the radar
 

Kürzlich hochgeladen

The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceanilsa9823
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️Delhi Call girls
 

Kürzlich hochgeladen (20)

The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female serviceCALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
CALL ON ➥8923113531 🔝Call Girls Badshah Nagar Lucknow best Female service
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS LiveVip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
Vip Call Girls Noida ➡️ Delhi ➡️ 9999965857 No Advance 24HRS Live
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 

Looping the Loop with SPL Iterators

  • 2. Looping the Loop with SPL Iterators What is an Iterator? An Iterator is an object that enables a programmer to traverse a container, particularly lists. A Behavioural Design Pattern (GoF)
  • 3. Looping the Loop with SPL Iterators What is an Iterator? $dataSet = ['A', 'B', 'C']; foreach($dataSet as $key => $value) { echo "{$key} => {$value}", PHP_EOL; }
  • 4. Looping the Loop with SPL Iterators What is an Iterator? 0 => A 1 => B 2 => C
  • 5. Looping the Loop with SPL Iterators What is an Iterator? $data = ['A', 'B', 'C']; $dataSet = new ArrayIterator($data); foreach($dataSet as $key => $value) { echo "{$key} => {$value}", PHP_EOL; }
  • 6. Looping the Loop with SPL Iterators What is an Iterator? 0 => A 1 => B 2 => C
  • 7. Looping the Loop with SPL Iterators What is an Iterator? interface Iterator extends Traversable { /* Methods */ abstract public current ( void ) : mixed abstract public key ( void ) : scalar abstract public next ( void ) : void abstract public rewind ( void ) : void abstract public valid ( void ) : bool }
  • 8. Looping the Loop with SPL Iterators What is an Iterator? $data = ['A', 'B', 'C']; $iterator = new ArrayIterator($data); $iterator->rewind(); while ($iterator->valid()) { $key = $iterator->key(); $value = $iterator->current(); echo "{$key} => {$value}", PHP_EOL; $iterator->next(); }
  • 9. Looping the Loop with SPL Iterators What is an Iterator? 0 => A 1 => B 2 => C
  • 10. Looping the Loop with SPL Iterators
  • 11. Looping the Loop with SPL Iterators The Iterable Tree iterable array Traversable Iterator Generator IteratorAggregate
  • 12. Looping the Loop with SPL Iterators The Iterable Tree Not all iterables are equal You can count the elements in an array ! Can you count the elements in an Iterator?
  • 13. Looping the Loop with SPL Iterators The Iterable Tree Not all iterables are equal You can access the elements of an array by their index ! Can you access the elements of an Iterator by index ?
  • 14. Looping the Loop with SPL Iterators The Iterable Tree Not all iterables are equal You can rewind an Iterator ! Can you rewind a Generator ?
  • 15. Looping the Loop with SPL Iterators The Iterable Tree Not all iterables are equal Iterator_* functions (e.g. iterator_to_array) work on Iterators ? Can you use iterator_* functions on an IteratorAggregate ?
  • 16. Looping the Loop with SPL Iterators The Iterable Tree iterable array Traversable Iterator Generator IteratorAggregate Iterable is a pseudo-type introduced in PHP 7.1. It accepts any array, or any object that implements the Traversable interface. Both of these types are iterable using foreach.
  • 17. Looping the Loop with SPL Iterators The Iterable Tree iterable array Traversable Iterator Generator IteratorAggregate An array in PHP is an ordered map, a type that associates values to keys. This type is optimized for several different uses; it can be treated as an array, list (vector), hash table (an implementation of a map), dictionary, collection, stack, queue, and more. The foreach control structure exists specifically for arrays.
  • 18. Looping the Loop with SPL Iterators The Iterable Tree iterable array Traversable Iterator Generator IteratorAggregate Abstract base interface to detect if a class is traversable using foreach. It cannot be implemented alone in Userland code; but instead must be implemented through either IteratorAggregate or Iterator. Internal (built-in) classes that implement this interface can be used in a foreach construct and do not need to implement IteratorAggregate or Iterator.
  • 19. Looping the Loop with SPL Iterators The Iterable Tree iterable array Traversable Iterator Generator IteratorAggregate Abstract base interface to detect if a class is traversable using foreach. It cannot be implemented alone in Userland code; but instead must be implemented through either IteratorAggregate or Iterator. PDOStatement DatePeriod SimpleXMLElement
  • 20. Looping the Loop with SPL Iterators The Iterable Tree iterable array Traversable Iterator Generator IteratorAggregate An Interface for external iterators or objects that can be iterated themselves internally. PHP already provides a number of iterators for many day to day tasks within the Standard PHP Library (SPL). SPL Iterators SPL DataStructures WeakMaps (PHP 8)
  • 21. Looping the Loop with SPL Iterators The Iterable Tree iterable array Traversable Iterator Generator IteratorAggregate Generators provide an easy way to implement simple user-defined iterators without the overhead or complexity of implementing a class that implements the Iterator interface. This flexibility does come at a cost, however: generators are forward-only iterators, and cannot be rewound once iteration has started.
  • 22. Looping the Loop with SPL Iterators The Iterable Tree iterable array Traversable Iterator Generator IteratorAggregate IteratorAggregate is a special interface for implementing an abstraction layer between user code and iterators. Implementing an IteratorAggregate will allow you to delegate the work of iteration to a separate class, while still enabling you to use the collection inside a foreach loop.
  • 23. Looping the Loop with SPL Iterators
  • 24. Looping the Loop with SPL Iterators Implementing an Iterator interface Iterator extends Traversable { /* Methods */ abstract public current ( void ) : mixed abstract public key ( void ) : scalar abstract public next ( void ) : void abstract public rewind ( void ) : void abstract public valid ( void ) : bool }
  • 25. Looping the Loop with SPL Iterators Implementing an Iterator class Utf8StringIterator implements Iterator { private $string; private $offset = 0; private $length = 0; public function __construct(string $string) { $this->string = $string; $this->length = iconv_strlen($string); } public function valid(): bool { return $this->offset < $this->length; } ... }
  • 26. Looping the Loop with SPL Iterators Implementing an Iterator class Utf8StringIterator implements Iterator { ... public function rewind(): void { $this->offset = 0; } public function current(): string { return iconv_substr($this->string, $this->offset, 1); } public function key(): int { return $this->offset; } public function next(): void { ++$this->offset; } }
  • 27. Looping the Loop with SPL Iterators Implementing an Iterator $stringIterator = new Utf8StringIterator('Καλησπέρα σε όλους'); foreach($stringIterator as $character) { echo "[{$character}]"; }
  • 28. Looping the Loop with SPL Iterators Implementing an Iterator [Κ][α][λ][η][σ][π][έ][ρ][α][ ][σ][ε][ ][ό][λ][ο][υ][ς]
  • 29. Looping the Loop with SPL Iterators Implementing an Iterator class FileLineIterator implements Iterator { private $fileHandle; private $line = 1; public function __construct(string $fileName) { $this->fileHandle = fopen($fileName, 'r'); } public function __destruct() { fclose($this->fileHandle); } }
  • 30. Looping the Loop with SPL Iterators Implementing an Iterator class FileLineIterator implements Iterator { ... public function current(): string { $fileData = fgets($this->fileHandle); return rtrim($fileData, "n"); } public function key(): int { return $this->line; } public function next(): void { ++$this->line; } }
  • 31. Looping the Loop with SPL Iterators Implementing an Iterator class FileLineIterator implements Iterator { ... public function rewind(): void { fseek($this->fileHandle, 0); $this->line = 1; } public function valid(): bool { return !feof($this->fileHandle); } }
  • 32. Looping the Loop with SPL Iterators Implementing an Iterator $fileLineIterator = new FileLineIterator(__FILE__); foreach($fileLineIterator as $lineNumber => $fileLine) { echo "{$lineNumber}: {$fileLine}", PHP_EOL; }
  • 33. Looping the Loop with SPL Iterators Implementing an Iterator 1: <?php 2: 3: class FileLineIterator implements Iterator { 4: private $fileHandle; 5: private $line = 1; 6: 7: public function __construct(string $fileName) { 8: $this->fileHandle = fopen($fileName, 'r’); 9: } 10: …
  • 34. Looping the Loop with SPL Iterators
  • 35. Looping the Loop with SPL Iterators class UserRepository { // ... public function all(): array { $userQuery = 'SELECT * FROM `users` ...'; $statement = $this->pdo->prepare($userQuery); $statement->execute(); $users = $statement->fetchAll(); return array_map(fn(array $user): User => User::fromArray($user), $users); } }
  • 36. Looping the Loop with SPL Iterators class UserRepository { // ... /** * @return User[] */ public function all(): array { $userQuery = 'SELECT * FROM `users` ...'; $statement = $this->pdo->prepare($userQuery); $statement->execute(); $users = $statement->fetchAll(); return array_map(fn(array $user): User => User::fromArray($user), $users); } }
  • 37. Looping the Loop with SPL Iterators class UserCollection extends ArrayIterator { }
  • 38. Looping the Loop with SPL Iterators class UserRepository { // ... public function all(): UserCollection { $userQuery = 'SELECT * FROM `users` ...'; $statement = $this->pdo->prepare($userQuery); $statement->execute(); $users = $statement->fetchAll(); return new UserCollection( array_map(fn(array $user): User => User::fromArray($user), $users) ); } }
  • 39. Looping the Loop with SPL Iterators class UserCollection extends ArrayIterator { public function current(): User { return User::fromArray(parent::current()); } }
  • 40. Looping the Loop with SPL Iterators class UserRepository { // ... public function all(): UserCollection { $userQuery = 'SELECT * FROM `users` ...'; $statement = $this->pdo->prepare($userQuery); $statement->execute(); $users = $statement->fetchAll(); return new UserCollection($users); } }
  • 41. Looping the Loop with SPL Iterators
  • 42. Looping the Loop with SPL Iterators ArrayIterator Implements: Countable ArrayAccess Serializable SeekableIterator (which entends Iterator)
  • 43. Looping the Loop with SPL Iterators ArrayIterator Implements: Countable
  • 44. Looping the Loop with SPL Iterators ArrayIterator – Countable interface Countable { /* Methods */ abstract public count ( void ) : int }
  • 45. Looping the Loop with SPL Iterators ArrayIterator – Countable $userData = ['user1', 'user2', 'user3', 'user4']; $userList = new UserList($userData); $userCount = count($userList); echo "There are {$userCount} users in this list", PHP_EOL;
  • 46. Looping the Loop with SPL Iterators ArrayIterator – Countable $userData = ['user1', 'user2', 'user3', 'user4']; $userList = new UserList($userData); echo "There are {$userList->count()} users in this list", PHP_EOL;
  • 47. Looping the Loop with SPL Iterators ArrayIterator – Countable There are 4 users in this list
  • 48. Looping the Loop with SPL Iterators ArrayIterator Implements: Countable ArrayAccess
  • 49. Looping the Loop with SPL Iterators ArrayIterator – ArrayAccess interface ArrayAccess { /* Methods */ abstract public offsetExists ( mixed $offset ) : bool abstract public offsetGet ( mixed $offset ) : mixed abstract public offsetSet ( mixed $offset , mixed $value ) : void abstract public offsetUnset ( mixed $offset ) : void }
  • 50. Looping the Loop with SPL Iterators ArrayIterator – ArrayAccess $userData = ['user1', 'user2', 'user3', 'user4']; $userList = new UserList($userData); echo "The 3rd entry in the list is {$userList[2]}", PHP_EOL;
  • 51. Looping the Loop with SPL Iterators ArrayIterator – ArrayAccess The 3rd entry in the list is user3
  • 52. Looping the Loop with SPL Iterators ArrayIterator Implements: Countable ArrayAccess Serializable
  • 53. Looping the Loop with SPL Iterators ArrayIterator – Serializable interface Serializable { /* Methods */ abstract public serialize ( void ) : string abstract public unserialize ( string $serialized ) : void }
  • 54. Looping the Loop with SPL Iterators ArrayIterator – Serializable $userData = ['user1', 'user2', 'user3', 'user4']; $userList = new UserList($userData); var_dump(serialize($userList));
  • 55. Looping the Loop with SPL Iterators ArrayIterator – Serializable string(117) "O:8:"UserList":4:{i:0;i:0;i:1;a:4:{i:0;s:5:"user1"; i:1;s:5:"user2";i:2;s:5:"user3";i:3;s:5:"user4";}i:2; a:0:{}i:3;N;}"
  • 56. Looping the Loop with SPL Iterators ArrayIterator Implements: Countable ArrayAccess Serializable SeekableIterator (which entends Iterator)
  • 57. Looping the Loop with SPL Iterators ArrayIterator – SeekableIterator SeekableIterator extends Iterator { /* Methods */ abstract public seek ( int $position ) : void /* Inherited methods */ abstract public Iterator::current ( void ) : mixed abstract public Iterator::key ( void ) : scalar abstract public Iterator::next ( void ) : void abstract public Iterator::rewind ( void ) : void abstract public Iterator::valid ( void ) : bool }
  • 58. Looping the Loop with SPL Iterators ArrayIterator – SeekableIterator $userData = ['user1', 'user2', 'user3', 'user4']; $userList = new UserList($userData); $userList->seek(2); while ($userList->valid()) { echo $userList->current(), PHP_EOL; $userList->next(); }
  • 59. Looping the Loop with SPL Iterators ArrayIterator – SeekableIterator user3 user4
  • 60. Looping the Loop with SPL Iterators ArrayIterator – SeekableIterator $userData = ['user1', 'user2', 'user3', 'user4']; $userList = new UserList($userData); $userList->seek(2); foreach($userList as $userName) { echo $userName, PHP_EOL; }
  • 61. Looping the Loop with SPL Iterators ArrayIterator – SeekableIterator user1 user2 user3 user4 
  • 62. Looping the Loop with SPL Iterators ArrayIterator – SeekableIterator $userData = ['A' => 'user1', 'B' => 'user2', 'C' => 'user3', 'D' => 'user4']; $userList = new UserList($userData); $userList->seek('C'); while ($userList->valid()) { echo $userList->current(), PHP_EOL; $userList->next(); }
  • 63. Looping the Loop with SPL Iterators ArrayIterator – SeekableIterator PHP7 Warning: ArrayIterator::seek() expects parameter 1 to be int, string given 
  • 64. Looping the Loop with SPL Iterators ArrayIterator – SeekableIterator PHP8 Fatal error: Uncaught TypeError ArrayIterator::seek(): Argument #1 ($position) must be of type int, string given 
  • 65. Looping the Loop with SPL Iterators ArrayIterator Implements: Countable ArrayAccess Serializable SeekableIterator (which entends Iterator) Also provides methods for sorting Doesn’t work with array_* functions
  • 66. Looping the Loop with SPL Iterators
  • 67. Looping the Loop with SPL Iterators
  • 68. Looping the Loop with SPL Iterators LimitIterator $userData = ['user1', 'user2', 'user3', 'user4']; $userList = new LimitIterator( new UserList($userData), 2, 1 ); foreach($userList as $value) { echo $value, PHP_EOL; }
  • 69. Looping the Loop with SPL Iterators LimitIterator user3
  • 70. Looping the Loop with SPL Iterators InfiniteIterator $weekdayNames = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat']; $todayOffset = (int) (new DateTime('2020-09-08'))->format('w'); $weekdayList = new LimitIterator( new InfiniteIterator( new ArrayIterator($weekdayNames) ), $todayOffset, 14 ); foreach($weekdayList as $dayOfWeek) { echo $dayOfWeek, PHP_EOL; }
  • 71. Looping the Loop with SPL Iterators InfiniteIterator Tues Wed Thurs Fri Sat Sun Mon Tues Wed Thurs Fri Sat Sun Mon
  • 72. Looping the Loop with SPL Iterators CallbackFilterIterator $weekdayNames = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat']; $todayOffset = (int) (new DateTime('2020-09-15'))->format('w'); $workdayList = new CallbackFilterIterator( new LimitIterator( new InfiniteIterator( new ArrayIterator($weekdayNames) ), $todayOffset, 14 ), fn($dayName): bool => $dayName !== 'Sat' && $dayName !== 'Sun' ); foreach($workdayList as $dayOfWeek) { echo $dayOfWeek, PHP_EOL; }
  • 73. Looping the Loop with SPL Iterators CallbackFilterIterator Tues Wed Thurs Fri Mon Tues Wed Thurs Fri Mon
  • 74. Looping the Loop with SPL Iterators
  • 75. Looping the Loop with SPL Iterators FilterIterator abstract FilterIterator extends IteratorIterator implements OuterIterator { /* Methods */ public abstract accept ( void ) : bool public __construct ( Iterator $iterator ) public current ( void ) : mixed public getInnerIterator ( void ) : Iterator public key ( void ) : mixed public next ( void ) : void public rewind ( void ) : void public valid ( void ) : bool }
  • 76. Looping the Loop with SPL Iterators FilterIterator class ImageFileIterator extends FilterIterator { // Overwrite the constructor to automagically create an inner iterator // to iterate the file system when given a path name. public function __construct(string $path) { parent::__construct(new FilesystemIterator($path)); } // Overwrite the accept method to perform a super simple test to // determine if the files found were images or not. public function accept(): bool { $fileObject = $this->getInnerIterator()->current(); return preg_match('/^(?:gif|jpe?g|png)$/i', $fileObject->getExtension()); } }
  • 77. Looping the Loop with SPL Iterators FilterIterator class ImageFileIterator extends FilterIterator { // Overwrite the constructor to automagically create an inner iterator // to iterate the file system when given a path name. public function __construct(string $path) { parent::__construct(new FilesystemIterator($path)); } // Overwrite the accept method to perform a super simple test to // determine if the files found were images or not. public function accept(): bool { return preg_match('/^(?:gif|jpe?g|png)$/i', $this->getExtension()); } }
  • 78. Looping the Loop with SPL Iterators FilterIterator $path = dirname(__FILE__); foreach(new ImageFileIterator($path) as $imageObject) { echo $imageObject->getBaseName(), PHP_EOL; }
  • 79. Looping the Loop with SPL Iterators FilterIterator anubis.jpg Carpet.jpg Crazy Newspaper Headlines.jpg elephpant.jpg Pie Chart.jpg PowerOfBooks.jpg Struggling-Team.png TeddyBears.jpg
  • 80. Looping the Loop with SPL Iterators Iterator Keys class ImageFileIterator extends FilterIterator { ... // Overwrite the key method to return the file extension as the key public function key(): string { return $this->getExtension(); } } foreach(new ImageFileIterator($path) as $extension => $imageObject) { echo "{$extension} => {$imageObject->getBaseName()}", PHP_EOL; }
  • 81. Looping the Loop with SPL Iterators Iterator Keys jpg => anubis.jpg jpg => Carpet.jpg jpg => Crazy Newspaper Headlines.jpg jpg => elephpant.jpg jpg => Pie Chart.jpg jpg => PowerOfBooks.jpg png => Struggling-Team.png jpg => TeddyBears.jpg
  • 82. Looping the Loop with SPL Iterators Iterator Keys class ImageFileIterator extends FilterIterator { ... // Overwrite the key method to return the last modified date/time as the key public function key(): DateTime { return DateTime::createFromFormat('U', $this->getMTime()); } } foreach(new ImageFileIterator($path) as $date => $imageObject) { echo "{$date->format('Y-m-d H:i:s')} => {$imageObject->getBaseName()}", PHP_EOL; }
  • 83. Looping the Loop with SPL Iterators Iterator Keys 2012-03-24 00:38:24 => anubis.jpg 2013-01-27 22:32:20 => Carpet.jpg 2013-03-07 12:16:24 => Crazy Newspaper Headlines.jpg 2012-02-16 22:31:56 => elephpant.jpg 2012-10-09 11:51:56 => Pie Chart.jpg 2012-07-17 12:22:32 => PowerOfBooks.jpg 2012-12-30 18:14:24 => Struggling-Team.png 2012-01-31 11:17:32 => TeddyBears.jpg
  • 84. Looping the Loop with SPL Iterators
  • 85. Looping the Loop with SPL Iterators MultipleIterator $dates = ['Q1-2019', 'Q2-2019', 'Q3-2019', 'Q4-2019']; $budget = [1200, 1300, 1400, 1500]; $expenditure = [1250, 1315, 1440, 1485]; $budgetElements = count($budget); for ($i = 0; $i < $budgetElements; $i++) { echo "{$dates[$i]} - {$budget[$i]}, {$expenditure[$i]}", PHP_EOL; }
  • 86. Looping the Loop with SPL Iterators MultipleIterator $dates = ['Q1-2019', 'Q2-2019', 'Q3-2019', 'Q4-2019']; $budget = [1200, 1300, 1400, 1500]; $expenditure = [1250, 1315, 1440, 1485]; foreach($dates as $key => $period) { echo "{$period} - {$budget[$key]}, {$expenditure[$key]}", PHP_EOL; }
  • 87. Looping the Loop with SPL Iterators MultipleIterator Q1-2019 - 1200, 1250 Q2-2019 - 1300, 1315 Q3-2019 - 1400, 1440 Q4-2019 - 1500, 1485
  • 88. Looping the Loop with SPL Iterators MultipleIterator function wrapArrayAsIterator(array $array) { return new ArrayIterator($array); } $combinedIterable = new MultipleIterator(MultipleIterator::MIT_KEYS_ASSOC); $combinedIterable->attachIterator(wrapArrayAsIterator($dates), 'date'); $combinedIterable->attachIterator(wrapArrayAsIterator($budget), 'budget'); $combinedIterable->attachIterator(wrapArrayAsIterator($expenditure), 'expenditure');
  • 89. Looping the Loop with SPL Iterators MultipleIterator foreach($combinedIterable as $dateValues) { echo $dateValues['date'], " - {$dateValues['budget']}, {$dateValues['expenditure']}", PHP_EOL; }
  • 90. Looping the Loop with SPL Iterators MultipleIterator foreach($combinedIterable as $dateValues) { [$date, $budget, $expenditure] = $dateValues; echo "{$date} - {$budget}, {$expenditure}", PHP_EOL; }
  • 91. Looping the Loop with SPL Iterators MultipleIterator Q1-2019 - 1200, 1250 Q2-2019 - 1300, 1315 Q3-2019 - 1400, 1440 Q4-2019 - 1500, 1485
  • 92. Looping the Loop with SPL Iterators MultipleIterator function wrapArrayAsIterator(array $array) { return new ArrayIterator($array); } $combinedIterable = new MultipleIterator(MultipleIterator::MIT_KEYS_ASSOC); $combinedIterable->attachIterator(wrapArrayAsIterator($dates), 'date'); $combinedIterable->attachIterator(wrapArrayAsIterator($budget), 'budget'); $combinedIterable->attachIterator(wrapArrayAsIterator($expenditure), 'expenditure');
  • 93. Looping the Loop with SPL Iterators MultipleIterator foreach($combinedIterable as $dateValues) { extract($dateValues); echo "{$date} - {$budget}, {$expenditure}", PHP_EOL; }
  • 94. Looping the Loop with SPL Iterators MultipleIterator Q1-2019 - 1200, 1250 Q2-2019 - 1300, 1315 Q3-2019 - 1400, 1440 Q4-2019 - 1500, 1485
  • 95. Looping the Loop with SPL Iterators MultipleIterator $allocations = $totalAdvance->allocateTo(count($cars)); foreach ($cars as $i => $car) { $car->setAdvance($allocations[$i]); }
  • 96. Looping the Loop with SPL Iterators MultipleIterator $allocations = $totalAdvance->allocateTo(count($cars)); $advanceAllocations = new MultipleIterator(MultipleIterator::MIT_KEYS_ASSOC); $advanceAllocations->attachIterator(ArrayIterator($cars), 'car'); $advanceAllocations->attachIterator(ArrayIterator($allocations), 'advance'); foreach($advanceAllocations as $advanceAllocation) { extract($advanceAllocation); $car->setAdvance($advance); }
  • 97. Looping the Loop with SPL Iterators
  • 98. Looping the Loop with SPL Iterators Inner and Outer Iterators Inner Iterator Implements Iterator, or extends a class that implements Iterator ArrayIterator SeekableIterator FilesystemIterator MultipleIterator
  • 99. Looping the Loop with SPL Iterators Inner and Outer Iterators Outer Iterator Implements OuterIterator, or extends an Iterator that already implements OuterIterator LimitIterator InfiniteIterator FilterIterator CallbackFilterIterator
  • 100. Looping the Loop with SPL Iterators Recursive Iterators A RecursiveIterator defines methods to allow iteration over hierarchical data structures. Nested Arrays (and Objects if using ArrayAccess) Filesystem Directories/Folders
  • 101. Looping the Loop with SPL Iterators
  • 102. Looping the Loop with SPL Iterators class UserRepository { // ... public function all(): UserCollection { $userQuery = 'SELECT * FROM `users` ...'; $statement = $this->pdo->prepare($userQuery); $statement->execute(); $users = $statement->fetchAll(); return new UserCollection( array_map(fn(array $user): User => User::fromArray($user), $users) ); } }
  • 103. Looping the Loop with SPL Iterators class UserRepository { // ... public function all(): Generator { $userQuery = 'SELECT * FROM `users` ...'; $statement = $this->pdo->prepare($userQuery); $statement->execute(); while ($user = $statement->fetch()) { yield User::fromArray($user); } } }
  • 104. Looping the Loop with SPL Iterators class UserRepository { // ... /** * @return Generator|User[] */ public function all(): Generator { $userQuery = 'SELECT * FROM `users` ...'; $statement = $this->pdo->prepare($userQuery); $statement->execute(); while ($user = $statement->fetch()) { yield User::fromArray($user); } } }
  • 105. Looping the Loop with SPL Iterators IteratorAggregate IteratorAggregate extends Traversable { /* Methods */ abstract public getIterator ( void ) : Traversable }
  • 106. Looping the Loop with SPL Iterators class UserCollection implements IteratorAggregate { private PDOStatement $pdoStatement; public function __construct(PDOStatement $pdoStatement) { $this->pdoStatement = $pdoStatement; } public function getIterator(): Traversable { $this->pdoStatement->execute(); while ($user = $this->pdoStatement->fetch()) { yield User::fromArray($user); } } }
  • 107. Looping the Loop with SPL Iterators class UserRepository { // ... public function all(): UserCollection { $userQuery = 'SELECT * FROM `users` ...'; $statement = $this->pdo->prepare($userQuery); return new UserCollection($statement); } }
  • 108. Looping the Loop with SPL Iterators Implementing a Fluent Nested Iterator $weekdayNames = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat']; $todayOffset = (int) (new DateTime('2020-09-15'))->format('w'); $workdayList = new CallbackFilterIterator( new LimitIterator( new InfiniteIterator( new ArrayIterator($weekdayNames) ), $todayOffset, 14 ), fn($dayName): bool => $dayName !== 'Sat' && $dayName !== 'Sun' ); foreach($workdayList as $dayOfWeek) { echo $dayOfWeek, PHP_EOL; }
  • 109. Looping the Loop with SPL Iterators Implementing a Fluent Nested Iterator class FluentNestedIterator implements IteratorAggregate { protected iterable $iterator; public function __construct(iterable $iterator) { $this->iterator = $iterator; } public function with(string $iterable, ...$args): self { $this->iterator = new $iterable($this->iterator, ...$args); return $this; } public function getIterator() { return $this->iterator; } }
  • 110. Looping the Loop with SPL Iterators Implementing a Fluent Nested Iterator $weekdayNames = ['Sun', 'Mon', 'Tues', 'Wed', 'Thurs', 'Fri', 'Sat']; $todayOffset = (int) (new DateTime('2020-10-08'))->format('w'); $workdayList = (new FluentNestedIterator(new ArrayIterator($weekdayNames))) ->with(InfiniteIterator::class) ->with(LimitIterator::class, $todayOffset, 14) ->with( CallbackFilterIterator::class, fn($dayName): bool => $dayName !== 'Sat' && $dayName !== 'Sun' ); foreach($workdayList as $dayOfWeek) { echo $dayOfWeek, PHP_EOL; }
  • 111. Looping the Loop with SPL Iterators Implementing a Fluent Nested Iterator Thurs Fri Mon Tues Wed Thurs Fri Mon Tues Wed
  • 112. Looping the Loop with SPL Iterators
  • 113. Looping the Loop with SPL Iterators Array Functions Don’t work with Traversables
  • 114. Looping the Loop with SPL Iterators Array Functions Don’t work with Traversables
  • 115. Looping the Loop with SPL Iterators Array Functions – Filter function filter(iterable $iterator, Callable $callback = null) { if ($callback === null) { $callback = 'iterableFilterNotEmpty'; } foreach ($iterator as $key => $value) { if ($callback($value)) { yield $key => $value; } } }
  • 116. Looping the Loop with SPL Iterators Array Functions – Filter $startTime = new DateTime('2015-11-23 13:20:00Z'); $endTime = new DateTime('2015-11-23 13:30:00Z'); $timeFilter = function($timestamp) use ($startTime, $endTime) { return $timestamp >= $startTime && $timestamp <= $endTime; }; $filteredTrackingData = filter( $gpxReader->getElements('trkpt'), $timeFilter, ARRAY_FILTER_USE_KEY ); foreach ($filteredTrackingData as $time => $element) { ... }
  • 117. Looping the Loop with SPL Iterators Array Functions – Filter 2015-11-23 13:24:40 latitude: 53.5441 longitude: -2.7416 elevation: 124 2015-11-23 13:24:49 latitude: 53.5441 longitude: -2.7416 elevation: 122 2015-11-23 13:24:59 latitude: 53.5441 longitude: -2.7416 elevation: 120 2015-11-23 13:25:09 latitude: 53.5441 longitude: -2.7417 elevation: 120 2015-11-23 13:25:19 latitude: 53.5441 longitude: -2.7417 elevation: 121 2015-11-23 13:25:29 latitude: 53.5441 longitude: -2.7417 elevation: 120 2015-11-23 13:25:39 latitude: 53.5441 longitude: -2.7417 elevation: 120
  • 118. Looping the Loop with SPL Iterators Array Functions – Filter Of course, we could always use a CallBackFilterIterator
  • 119. Looping the Loop with SPL Iterators Array Functions – Map function map(Callable $callback, iterable $iterator) { foreach ($iterator as $key => $value) { yield $key => $callback($value); } }
  • 120. Looping the Loop with SPL Iterators Array Functions – Map $distanceCalculator = new GpxReaderHelpersDistanceCalculator(); $mappedTrackingData = map( [$distanceCalculator, 'setDistanceProperty'], $gpxReader->getElements('trkpt') ); foreach ($mappedTrackingData as $time => $element) { ... }
  • 121. Looping the Loop with SPL Iterators Array Functions – Map 2015-11-23 14:57:07 latitude: 53.5437 longitude: -2.7424 elevation: 103 distance from previous point: 6.93 m 2015-11-23 14:57:17 latitude: 53.5437 longitude: -2.7424 elevation: 100 distance from previous point: 1.78 m 2015-11-23 14:57:27 latitude: 53.5438 longitude: -2.7425 elevation: 89 distance from previous point: 11.21 m 2015-11-23 14:57:37 latitude: 53.5439 longitude: -2.7424 elevation: 83 distance from previous point: 9.23 m 2015-11-23 14:57:47 latitude: 53.5439 longitude: -2.7425 elevation: 92 distance from previous point: 5.40 m
  • 122. Looping the Loop with SPL Iterators Array Functions – Walk iterator_apply() iterator_apply( Traversable $iterator, Callable $callback [, array $args = NULL ] ) : int
  • 123. Looping the Loop with SPL Iterators Array Functions – Reduce function reduce(iterable $iterator, Callable $callback, $initial = null) { $result = $initial; foreach($iterator as $value) { $result = $callback($result, $value); } return $result; }
  • 124. Looping the Loop with SPL Iterators Array Functions – Reduce $distanceCalculator = new GpxReaderHelpersDistanceCalculator(); $totalDistance = reduce( map( [$distanceCalculator, 'setDistanceProperty'], $gpxReader->getElements('trkpt') ), function($runningTotal, $value) { return $runningTotal + $value->distance; }, 0.0 );
  • 125. Looping the Loop with SPL Iterators Array Functions – Reduce Total distance travelled is 4.33 km
  • 126. Looping the Loop with SPL Iterators Array Functions – Other Iterator Functions Iterator_count() iterator_count ( Traversable $iterator ) : int
  • 127. Looping the Loop with SPL Iterators Array Functions – Other Iterator Functions Iterator_to_array() iterator_to_array ( Traversable $iterator [, bool $use_keys = TRUE ] ) : array
  • 128. Looping the Loop with SPL Iterators
  • 129. Looping the Loop with SPL Iterators A Functional Guide to Cat Herding with PHP Generators • https://markbakeruk.net/2016/01/19/a-functional-guide-to-cat-herding-with-php-generators/ • https://markbakeruk.net/2020/01/05/filtering-and-mapping-with-spl-iterators/ • https://markbakeruk.net/2019/12/31/parallel-looping-in-php-with-spls-multipleiterator/
  • 130. Looping the Loop with SPL Iterators Iterating PHP Iterators By Cal Evans https://leanpub.com/iteratingphpiterators by Joshua Thijssen https://www.phparch.com/books/mastering-the-spl-library/
  • 131. Who am I? Mark Baker Most Recently: Senior Software Engineer MessageBird BV, Amsterdam Coordinator and Developer of: Open Source PHPOffice library PHPExcel, PHPWord, PHPPowerPoint, PHPProject, PHPVisio Minor contributor to PHP core (SPL DataStructures) Other small open source libraries available on github @Mark_Baker https://github.com/MarkBaker http://uk.linkedin.com/pub/mark-baker/b/572/171 http://markbakeruk.net Looping the Loop with SPL Iterators