SlideShare a Scribd company logo
Electrify your
Code with
PHP Generators
PHP Generators
• http://www.slideshare.net/MarkBakerUK/generators-49071693
PHP Generators
Wikipedia defines a Generator as:
A generator is very similar to a function that returns an array, in that
a generator has parameters, can be called, and generates a
sequence of values. However, instead of building an array containing
all the values and returning them all at once, a generator yields the
values one at a time, which requires less memory and allows the
caller to get started processing the first few values immediately. In
short, a generator looks like a function but behaves like an iterator.
PHP Generators
• Introduced in PHP 5.5
• Iterable (Traversable) Objects
• Can return a series of values, one at a time
• Maintain state between iterations
• Can accept values when sent to the generator
• Similar to enumerators in Ruby, or Sequence Expressions in F#
PHP Generators
• Don’t
• Add anything to PHP that couldn’t be done before
• Do
• Allow you to perform iterative operations without an array to iterate
• Potentially reduce memory use
• Potentially faster than iterating over an array
• Can be type-hinted in function/method definitions
• Potentially cleaner and shorter code
• Add semantics to your code
PHP Generators
• Automatically created when PHP identifies a function or method
containing the “yield” keyword
function myGeneration() {
yield 1;
}
$generator = myGeneration();
var_dump($generator);
object(Generator)#1 (0) { }
PHP Generators
• Implemented as an Object
final class Generator implements Iterator {
mixed current( void );
mixed key( void );
void next( void );
void rewind( void );
mixed send( mixed $value );
mixed throw( Exception $exception );
bool valid( void );
public void __wakeup ( void )
}
• Can’t be extended
PHP Generators
function xrange($lower, $upper) {
for ($i = $lower; $i <= $upper; ++$i) {
yield $i;
}
}
$rangeGenerator = xrange(0,10);
while ($rangeGenerator->valid()) {
$key = $rangeGenerator->key();
$value = $rangeGenerator->current();
echo $key , ' -> ' , $value, PHP_EOL;
$rangeGenerator->next();
}
PHP Generators
function xrange($lower, $upper) {
for ($i = $lower; $i <= $upper; ++$i) {
yield $i;
}
}
foreach (xrange(0,10) as $key => $value) {
echo $key , ' -> ' , $value, PHP_EOL;
}
PHP Generators
foreach (range(0,65535) as $i => $value) {
echo $i , ' -> ' , $value, PHP_EOL;
}
function xrange($lower, $upper) {
for ($i = $lower; $i <= $upper; ++$i) {
yield $i;
}
}
foreach (xrange(0, 65535) as $i => $value) {
echo $i , ' -> ' , $value, PHP_EOL;
}
for($i = 0; $i <= 65535; ++$i) {
echo $i , ' -> ' , $value, PHP_EOL;
}
Time: 0.0183 s
Current Memory: 123.44 k
Peak Memory: 5500.11 k
Time: 0.0135 s
Current Memory: 124.33 k
Peak Memory: 126.84 k
Time: 0.0042 s
Current Memory: 122.92 k
Peak Memory: 124.49 k
PHP Generators
function xlColumnRange($lower, $upper) {
++$upper;
for ($i = $lower; $i != $upper; ++$i) {
yield $i;
}
}
foreach (xlColumnRange('A', 'CQ') as $i => $value) {
printf('%3d -> %2s', $i, $value);
echo (($i > 0) && ($i+1 % 5 == 0)) ?
PHP_EOL :
"t";
}
0 -> A 1 -> B 2 -> C 3 -> D 4 -> E
5 -> F 6 -> G 7 -> H 8 -> I 9 -> J
10 -> K 11 -> L 12 -> M 13 -> N 14 -> O
15 -> P 16 -> Q 17 -> R 18 -> S 19 -> T
20 -> U 21 -> V 22 -> W 23 -> X 24 -> Y
25 -> Z 26 -> AA 27 -> AB 28 -> AC 29 -> AD
30 -> AE 31 -> AF 32 -> AG 33 -> AH 34 -> AI
35 -> AJ 36 -> AK 37 -> AL 38 -> AM 39 -> AN
40 -> AO 41 -> AP 42 -> AQ 43 -> AR 44 -> AS
45 -> AT 46 -> AU 47 -> AV 48 -> AW 49 -> AX
50 -> AY 51 -> AZ 52 -> BA 53 -> BB 54 -> BC
55 -> BD 56 -> BE 57 -> BF 58 -> BG 59 -> BH
60 -> BI 61 -> BJ 62 -> BK 63 -> BL 64 -> BM
65 -> BN 66 -> BO 67 -> BP 68 -> BQ 69 -> BR
70 -> BS 71 -> BT 72 -> BU 73 -> BV 74 -> BW
75 -> BX 76 -> BY 77 -> BZ 78 -> CA 79 -> CB
80 -> CC 81 -> CD 82 -> CE 83 -> CF 84 -> CG
85 -> CH 86 -> CI 87 -> CJ 88 -> CK 89 -> CL
90 -> CM 91 -> CN 92 -> CO 93 -> CP 94 -> CQ
PHP Generators
$isEven = function ($value) {
return !($value & 1);
};
$isOdd = function ($value) {
return $value & 1;
};
function xFilter(callable $callback, array $args=array()) {
foreach ($args as $arg)
if (call_user_func($callback, $arg))
yield $arg;
}
PHP Generators
$data = range(1,10);
echo 'xFilter for Odd Numbers', PHP_EOL;
foreach (xFilter($isOdd, $data) as $i)
echo('num is: '.$i.PHP_EOL);
echo 'xFilter for Even Numbers', PHP_EOL;
foreach (xFilter($isEven, $data) as $i)
echo('num is: '.$i.PHP_EOL);
xFilter for Odd Numbers
num is: 1
num is: 3
num is: 5
num is: 7
num is: 9
xFilter for Even Numbers
num is: 2
num is: 4
num is: 6
num is: 8
num is: 10
PHP Generators
• Can return both a value and a “pseudo” key
• By default
• The key is an integer value
• Starting with 0 for the first iteration
• Incrementing by 1 each iteration
• Accessed from foreach() as:
foreach(generator() as $key => $value) {}
• or using
$key = $generatorObject->key();
PHP Generators
• Default key behaviour can be changed
• Syntax is:
yield $key => $value;
• Unlike array keys:
• “Pseudo” keys can be any PHP datatype
• “Pseudo” key values can be duplicated
PHP Generators
function xrange($lower, $upper) {
$k = $upper;
for ($i = $lower; $i <= $upper; ++$i) {
yield $k-- => $i;
}
}
foreach (xrange(0, 8) as $i => $value) {
echo $i, ' -> ', $value, PHP_EOL;
}
8 -> 0
7 -> 1
6 -> 2
5 -> 3
4 -> 4
3 -> 5
2 -> 6
1 -> 7
0 -> 8
PHP Generators
function duplicateKeys($lower, $upper) {
for ($i = $lower; $i <= $upper; ++$i) {
yield (($i-1) % 3) + 1 => $i;
}
}
foreach (duplicateKeys(1,15) as $i => $value){
echo $i , ' -> ' , $value, PHP_EOL;
}
1 -> 1
2 -> 2
3 -> 3
1 -> 4
2 -> 5
3 -> 6
1 -> 7
2 -> 8
3 -> 9
1 -> 10
2 -> 11
3 -> 12
1 -> 13
2 -> 14
3 -> 15
PHP Generators
function duplicateKeys($string) {
$string = strtolower($string);
$length = strlen($string);
for ($i = 0; $i < $length; ++$i) {
yield strtoupper($string[$i]) => $string[$i];
}
}
foreach (duplicateKeys('badass') as $key => $value) {
echo $key , ' -> ' , $value, PHP_EOL;
}
B -> b
A -> a
D -> d
A -> a
S -> s
S -> s
PHP Generators
function floatKeys($lower, $upper) {
for ($i = $lower; $i <= $upper; ++$i) {
yield ($i / 5) => $i;
}
}
foreach (floatKeys(1,16) as $i => $value) {
printf(
'%0.2f -> %2d' . PHP_EOL,
$i,
$value
);
}
0.20 -> 1
0.40 -> 2
0.60 -> 3
0.80 -> 4
1.00 -> 5
1.20 -> 6
1.40 -> 7
1.60 -> 8
1.80 -> 9
2.00 -> 10
2.20 -> 11
2.40 -> 12
2.60 -> 13
2.80 -> 14
3.00 -> 15
3.20 -> 16
PHP Generators
• It is possible to access generated values “by reference”
• The generator must be declared “by reference”
• The yielded value must be a variable, and cannot be an expression
PHP Generators
function &byReference2($size) {
for($val=1, $key=1; $key <= $size; ++$val, ++$key) {
yield $key => $val;
}
}
$size = 10;
foreach (byReference2($size) as $key => &$value) {
echo $key, ' => ', $value, ' => ',
($value += $value - 1), PHP_EOL;
}
echo PHP_EOL;
1 => 1 => 1
2 => 2 => 3
3 => 4 => 7
4 => 8 => 15
5 => 16 => 31
6 => 32 => 63
7 => 64 => 127
8 => 128 => 255
9 => 256 => 511
10 => 512 => 1023
PHP Generators
• Data can be passed to the generator
• Sometimes called a “Coroutine” when used in this way
• Not strictly accurate, they are more strictly a “Semicoroutine”
• They can form the basis for a “Coroutine” with the addition of a top-level
dispatcher routine
• Syntax is:
$value = yield;
• Calling script uses the “send()” method:
$generatorObject->send($value);
PHP Generators
$data = array(
'Squirtle',
'Jigglypuff',
'Charmander',
'Bulbasaur',
'White DPC Elephpant',
);
function generatorSend() {
while (true) {
$cityName = yield;
echo $cityName, PHP_EOL;
}
}
$generatorObject = generatorSend();
foreach($data as $value) {
$generatorObject->send($value);
}
echo PHP_EOL, 'Gotta Collect 'em all', PHP_EOL;
Squirtle
Jigglypuff
Charmander
Bulbasaur
White DPC Elephpant
Gotta Collect 'em All
PHP Generators
$logFileName = __DIR__ . '/error.log';
function logger($logFileName) {
$f = fopen($logFileName, 'a');
while ($logentry = yield) {
fwrite(
$f,
(new DateTime())->format('Y-m-d H:i:s ') .
$logentry .
PHP_EOL
);
}
}
$logger = logger($logFileName);
for($i = 0; $i < 12; ++$i) {
$logger->send('Message #' . $i );
}
PHP Generators
• It is possible to combine a Generator
to both send and accept data
PHP Generators
function generatorSend($limit) {
for ($i = 1; $i <= $limit; ++$i) {
yield $i => pow($i, $i);
$continue = yield;
if (!$continue)
break;
}
}
$generatorObject = generatorSend(100);
while ($generatorObject->valid()) {
$key = $generatorObject->key();
$value = $generatorObject->current();
$generatorObject->next();
$generatorObject->send($key >= 10);
echo $key, ' -> ', $value, PHP_EOL;
}
1 -> 1
2 -> 4
3 -> 27
4 -> 256
5 -> 3125
6 -> 46656
7 -> 823543
8 -> 16777216
9 -> 387420489
10 -> 10000000000
PHP Generators (Gotcha)
function generatorSend($limit) {
for ($i = 1; $i <= $limit; ++$i) {
yield pow($i, $i);
$continue = yield;
if (!$continue)
break;
}
}
$generatorObject = generatorSend(100);
while ($generatorObject->valid()) {
$key = $generatorObject->key();
$value = $generatorObject->current();
$generatorObject->next();
$generatorObject->send($key >= 10);
echo $key, ' -> ', $value, PHP_EOL;
}
0 -> 1
2 -> 4
4 -> 27
6 -> 256
8 -> 3125
10 -> 46656
PHP Generators
function generatorSend($limit) {
for ($i = 1; $i <= $limit; ++$i) {
$continue = (yield pow($i, $i));
if (!$continue)
break;
}
}
$generatorObject = generatorSend(100);
while($generatorObject->valid()) {
$key = $generatorObject->key();
$value = $generatorObject->current();
echo $key, ' -> ', $value, PHP_EOL;
$generatorObject->send($key >= 10);
}
0 -> 1
1 -> 4
2 -> 27
3 -> 256
4 -> 3125
5 -> 46656
6 -> 823543
7 -> 16777216
8 -> 387420489
9 -> 10000000000
PHP Generators (Gotcha)
function generatorSend($limit) {
for ($i = 1; $i <= $limit; ++$i) {
$continue = (yield pow($i, $i));
if (!$continue)
break;
}
}
$generatorObject = generatorSend(100);
foreach($generatorObject as $key => $value) {
echo $key, ' -> ', $value, PHP_EOL;
$generatorObject->send($key >= 10);
}
0 -> 1
PHP Generators (Gotcha)
function generatorSend($limit) {
for ($i = 1; $i <= $limit; ++$i) {
$continue = (yield pow($i, $i));
if (!$continue && $continue !== null)
break;
}
}
$generatorObject = generatorSend(100);
foreach($generatorObject as $key => $value) {
echo $key, ' -> ', $value, PHP_EOL;
$generatorObject->send($key >= 10);
}
1 -> 1
3 -> 27
5 -> 3125
7 -> 823543
9 -> 387420489
11 -> 285311670611
PHP Generators (Gotcha)
function generatorSend($limit) {
for ($i = 1; $i <= $limit; ++$i) {
$continue = (yield pow($i, $i));
if (!$continue && $continue !== null)
break;
elseif (!$continue && $continue === null)
--$i;
}
}
$generatorObject = generatorSend(100);
foreach($generatorObject as $key => $value) {
echo $key, ' -> ', $value, PHP_EOL;
$generatorObject->send($key >= 10);
}
1 -> 1
2 -> 4
3 -> 27
4 -> 256
5 -> 3125
6 -> 46656
7 -> 823543
8 -> 16777216
9 -> 387420489
10 -> 10000000000
PHP Generators
• By sending data into a Generator
it is possible to change its behaviour
PHP Generators
function diamond($size) {
$i = $key = 1;
do {
$ascending = (yield $key => str_repeat(' ', $size - $i) .
str_repeat('*', $i*2-1) . str_repeat(' ', $size - $i));
if ($ascending !== null) {
($ascending) ? ++$i : --$i;
++$key;
}
} while($i > 0);
}
$size = 5;
$diamond = diamond($size);
foreach ($diamond as $key => $value) {
echo sprintf('%2d', $key), ' => ', $value, PHP_EOL;
$diamond->send($key < $size);
}
1 => *
2 => ***
3 => *****
4 => *******
5 => *********
6 => *******
7 => *****
8 => ***
9 => *
PHP Generators
function adjustableIncrementor($value = 1, $increment = 1) {
do {
$increment = (yield $value);
$value += $increment;
} while ($value <= PHP_INT_MAX);
}
$incrementor = adjustableIncrementor();
foreach ($incrementor as $increment) {
echo number_format($increment), PHP_EOL;
$incrementor->send($increment);
}
1
2
4
8
16
32
64
128
256
512
1,024
...
268,435,456
536,870,912
1,073,741,824
PHP Generators
function adjustableIncrementor($value = 1, $increment = 1) {
do {
$increment = (yield $value);
$value += $increment;
} while ($value <= PHP_INT_MAX);
}
$incrementor = adjustableIncrementor();
foreach ($incrementor as $increment) {
echo number_format($increment), PHP_EOL;
$incrementor->send(pow(10, strlen($increment)-1));
}
1
2
3
...
9
10
20
30
...
90
100
200
300
...
900
1,000
...
PHP Generators
• We can also throw an Exception into a Generator
• A Try/Catch block should be defined in the Generator
• We use the Generator’s “throw()” method from the calling code
$generatorObject->throw(new Exception(‘xyz’));
• Useful for terminating a Generator loop if we don’t want to code a
send() in every iteration
PHP Generators
function filteredNumbers(Callable $filter) {
$i = 1;
try {
do {
if (call_user_func($filter, $i)) {
yield $i;
}
} while ($i++ <= PHP_INT_MAX);
} catch (Exception $e) {
echo $e->getMessage(), PHP_EOL;
}
}
PHP Generators
$primes = filteredNumbers($isPrime);
foreach ($primes as $counter => $prime) {
if ($prime > 50) {
$primes->throw(
new Exception('Enough already')
);
continue;
}
echo $prime, PHP_EOL;
}
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
Enough already
PHP Generators
• You can’t pass Generators as arguments to array functions
So you can’t call array_map() or array_reduce()with a
Generator instead of an array argument
• But by passing a Generator as an argument to another
Generator, we can chain Generators
Allowing us to simulate array_map() or array_reduce()
PHP Generators
function filteredNumbers(Callable $filter) {
$i = 1;
do {
if (call_user_func($filter, $i)) {
yield $i;
}
} while ($i++ <= PHP_INT_MAX);
}
PHP Generators
function filteredValueLimit(Traversable $filter, $limit) {
foreach ($filter as $value) {
if ($value > $limit) {
break;
}
yield $value;
}
}
PHP Generators
function mappedFilterList(Traversable $filter, Callable $callback) {
foreach ($filter as $value) {
yield $value => call_user_func($callback, $value);
}
}
PHP Generators
$primes = filteredNumbers($isPrime);
$primes64 = filteredValueLimit($primes, 64);
$primesSquared = mappedFilterList(
$primes64,
function($value) {
return $value * $value;
}
);
foreach ($primesSquared as $primeSquared) {
echo $prime, ' => ', $primeSquared, PHP_EOL;
}
2 => 4
3 => 9
5 => 25
7 => 49
11 => 121
13 => 169
17 => 289
19 => 361
23 => 529
29 => 841
31 => 961
37 => 1369
41 => 1681
43 => 1849
47 => 2209
53 => 2809
59 => 3481
61 => 3721
PHP Generators
function reduceFilterList(Traversable $filter, Callable $callback, $initial) {
$result = $initial;
foreach($filter as $value) {
$result = call_user_func($callback, $value, $result);
}
yield $result;
}
PHP Generators
$primes = filteredNumbers2($isPrime);
$primes64 = filteredValueLimit($primes, 64);
$sumPrimes = reduceFilterList(
$primes64,
function($value, $initial) {
return $value + $initial;
},
0
);
$sumPrime = $sumPrimes->current();
echo $sumPrime, PHP_EOL;
501
PHP Generators
• Limitations
• Can’t be Extended
• Can’t be Serialized
• Can’t be “Rewound”
PHP Generators
• Additional Reading:
• http://blog.ircmaxell.com/2012/07/what-generators-can-do-for-you.html
• http://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html
• https://markbakeruk.net/2016/01/19/a-functional-guide-to-cat-herding-with-php-
generators/
Electrify your code with
PHP Generators
?
Questions
Who am I?
Mark Baker
Design and Development Manager
InnovEd (Innovative Solutions for Education) Learning Ltd
Coordinator and Developer of:
Open Source PHPOffice library
PHPExcel, PHPWord, PHPPowerPoint, PHPProject, PHPVisio
Minor contributor to PHP core
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

More Related Content

PPTX
Looping the Loop with SPL Iterators
Mark Baker
 
PDF
PHP Language Trivia
Nikita Popov
 
PDF
Design Patterns avec PHP 5.3, Symfony et Pimple
Hugo Hamon
 
PPTX
Generated Power: PHP 5.5 Generators
Mark Baker
 
PDF
Doctrine MongoDB ODM (PDXPHP)
Kris Wallsmith
 
PDF
Static Optimization of PHP bytecode (PHPSC 2017)
Nikita Popov
 
PDF
PHP 7 – What changed internally? (Forum PHP 2015)
Nikita Popov
 
PDF
News of the Symfony2 World
Fabien Potencier
 
Looping the Loop with SPL Iterators
Mark Baker
 
PHP Language Trivia
Nikita Popov
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Hugo Hamon
 
Generated Power: PHP 5.5 Generators
Mark Baker
 
Doctrine MongoDB ODM (PDXPHP)
Kris Wallsmith
 
Static Optimization of PHP bytecode (PHPSC 2017)
Nikita Popov
 
PHP 7 – What changed internally? (Forum PHP 2015)
Nikita Popov
 
News of the Symfony2 World
Fabien Potencier
 

What's hot (20)

PDF
Advanced symfony Techniques
Kris Wallsmith
 
PDF
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
James Titcumb
 
PDF
Perl6 grammars
Andrew Shitov
 
PPTX
Speed up your developments with Symfony2
Hugo Hamon
 
PPT
Corephpcomponentpresentation 1211425966721657-8
PrinceGuru MS
 
PPTX
PHP PPT FILE
AbhishekSharma2958
 
PDF
Nubilus Perl
Flavio Poletti
 
PDF
SPL: The Missing Link in Development
jsmith92
 
PDF
PHP 5.3 and Lithium: the most rad php framework
G Woo
 
KEY
Perl Web Client
Flavio Poletti
 
PDF
Just-In-Time Compiler in PHP 8
Nikita Popov
 
PDF
Silex meets SOAP & REST
Hugo Hamon
 
PDF
PHPCon 2016: PHP7 by Witek Adamus / XSolve
XSolve
 
PDF
The Zen of Lithium
Nate Abele
 
PDF
Xlab #1: Advantages of functional programming in Java 8
XSolve
 
PPTX
New in php 7
Vic Metcalfe
 
PDF
Php tips-and-tricks4128
PrinceGuru MS
 
PDF
PHP 7 – What changed internally? (PHP Barcelona 2015)
Nikita Popov
 
PPTX
A Functional Guide to Cat Herding with PHP Generators
Mark Baker
 
PDF
Symfony2 - WebExpo 2010
Fabien Potencier
 
Advanced symfony Techniques
Kris Wallsmith
 
Mirror, mirror on the wall: Building a new PHP reflection library (DPC 2016)
James Titcumb
 
Perl6 grammars
Andrew Shitov
 
Speed up your developments with Symfony2
Hugo Hamon
 
Corephpcomponentpresentation 1211425966721657-8
PrinceGuru MS
 
PHP PPT FILE
AbhishekSharma2958
 
Nubilus Perl
Flavio Poletti
 
SPL: The Missing Link in Development
jsmith92
 
PHP 5.3 and Lithium: the most rad php framework
G Woo
 
Perl Web Client
Flavio Poletti
 
Just-In-Time Compiler in PHP 8
Nikita Popov
 
Silex meets SOAP & REST
Hugo Hamon
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
XSolve
 
The Zen of Lithium
Nate Abele
 
Xlab #1: Advantages of functional programming in Java 8
XSolve
 
New in php 7
Vic Metcalfe
 
Php tips-and-tricks4128
PrinceGuru MS
 
PHP 7 – What changed internally? (PHP Barcelona 2015)
Nikita Popov
 
A Functional Guide to Cat Herding with PHP Generators
Mark Baker
 
Symfony2 - WebExpo 2010
Fabien Potencier
 
Ad

Viewers also liked (20)

PDF
Diving deep into twig
Matthias Noback
 
ODP
Elastic Searching With PHP
Lea Hänsenberger
 
PDF
Techniques d'accélération des pages web
Jean-Pierre Vincent
 
PDF
Get Soaked - An In Depth Look At PHP Streams
Davey Shafik
 
PDF
Automation using-phing
Rajat Pandit
 
ODP
PHP5.5 is Here
julien pauli
 
PDF
The quest for global design principles (SymfonyLive Berlin 2015)
Matthias Noback
 
PDF
Mocking Demystified
Marcello Duarte
 
PDF
Top tips my_sql_performance
afup Paris
 
PDF
Understanding Craftsmanship SwanseaCon2015
Marcello Duarte
 
PDF
Why elasticsearch rocks!
tlrx
 
PDF
Writing infinite scalability web applications with PHP and PostgreSQL
Gabriele Bartolini
 
PDF
Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Bruno Boucard
 
PDF
L'ABC du BDD (Behavior Driven Development)
Arnauld Loyer
 
PDF
Performance serveur et apache
afup Paris
 
PDF
Behat 3.0 meetup (March)
Konstantin Kudryashov
 
PDF
TDD with PhpSpec - Lone Star PHP 2016
CiaranMcNulty
 
PDF
Caching on the Edge
Fabien Potencier
 
PDF
The Wonderful World of Symfony Components
Ryan Weaver
 
PDF
PHPSpec - the only Design Tool you need - 4Developers
Kacper Gunia
 
Diving deep into twig
Matthias Noback
 
Elastic Searching With PHP
Lea Hänsenberger
 
Techniques d'accélération des pages web
Jean-Pierre Vincent
 
Get Soaked - An In Depth Look At PHP Streams
Davey Shafik
 
Automation using-phing
Rajat Pandit
 
PHP5.5 is Here
julien pauli
 
The quest for global design principles (SymfonyLive Berlin 2015)
Matthias Noback
 
Mocking Demystified
Marcello Duarte
 
Top tips my_sql_performance
afup Paris
 
Understanding Craftsmanship SwanseaCon2015
Marcello Duarte
 
Why elasticsearch rocks!
tlrx
 
Writing infinite scalability web applications with PHP and PostgreSQL
Gabriele Bartolini
 
Si le tdd est mort alors pratiquons une autopsie mix-it 2015
Bruno Boucard
 
L'ABC du BDD (Behavior Driven Development)
Arnauld Loyer
 
Performance serveur et apache
afup Paris
 
Behat 3.0 meetup (March)
Konstantin Kudryashov
 
TDD with PhpSpec - Lone Star PHP 2016
CiaranMcNulty
 
Caching on the Edge
Fabien Potencier
 
The Wonderful World of Symfony Components
Ryan Weaver
 
PHPSpec - the only Design Tool you need - 4Developers
Kacper Gunia
 
Ad

Similar to Electrify your code with PHP Generators (20)

ODP
Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...
dantleech
 
PDF
lab4_php
tutorialsruby
 
PDF
lab4_php
tutorialsruby
 
ODP
Incredible Machine with Pipelines and Generators
dantleech
 
PPTX
php programming.pptx
rani marri
 
PDF
08 Advanced PHP #burningkeyboards
Denis Ristic
 
PPT
Web Technology_10.ppt
Aftabali702240
 
PDF
How to run PHP code in XAMPP.docx (1).pdf
rajeswaria21
 
PDF
Zend Certification PHP 5 Sample Questions
Jagat Kothari
 
PPT
Synapse india complain sharing info about php chaptr 26
SynapseindiaComplaints
 
PPTX
Arrays in PHP
davidahaskins
 
PDF
Generating Power with Yield
Jason Myers
 
PDF
Cryptography in PHP: use cases
Enrico Zimuel
 
PDF
PHP Lec 2.pdfsssssssssssssssssssssssssss
ksjawyyy
 
PPT
PHP Scripting
Reem Alattas
 
DOCX
PHP record- with all programs and output
KavithaK23
 
PDF
잘 알려지지 않은 Php 코드 활용하기
형우 안
 
PPTX
Php Syntax Basics in one single course in nutshell
binzbinz3
 
PPT
Php course-in-navimumbai
vibrantuser
 
Building and Incredible Machine with Pipelines and Generators in PHP (IPC Ber...
dantleech
 
lab4_php
tutorialsruby
 
lab4_php
tutorialsruby
 
Incredible Machine with Pipelines and Generators
dantleech
 
php programming.pptx
rani marri
 
08 Advanced PHP #burningkeyboards
Denis Ristic
 
Web Technology_10.ppt
Aftabali702240
 
How to run PHP code in XAMPP.docx (1).pdf
rajeswaria21
 
Zend Certification PHP 5 Sample Questions
Jagat Kothari
 
Synapse india complain sharing info about php chaptr 26
SynapseindiaComplaints
 
Arrays in PHP
davidahaskins
 
Generating Power with Yield
Jason Myers
 
Cryptography in PHP: use cases
Enrico Zimuel
 
PHP Lec 2.pdfsssssssssssssssssssssssssss
ksjawyyy
 
PHP Scripting
Reem Alattas
 
PHP record- with all programs and output
KavithaK23
 
잘 알려지지 않은 Php 코드 활용하기
형우 안
 
Php Syntax Basics in one single course in nutshell
binzbinz3
 
Php course-in-navimumbai
vibrantuser
 

More from Mark Baker (20)

PPTX
Looping the Loop with SPL Iterators
Mark Baker
 
PPTX
Looping the Loop with SPL Iterators
Mark Baker
 
PPTX
Deploying Straight to Production
Mark Baker
 
PPTX
Deploying Straight to Production
Mark Baker
 
PPTX
Deploying Straight to Production
Mark Baker
 
PPTX
A Brief History of Elephpants
Mark Baker
 
PPTX
Aspects of love slideshare
Mark Baker
 
PPTX
Does the SPL still have any relevance in the Brave New World of PHP7?
Mark Baker
 
PPTX
A Brief History of ElePHPants
Mark Baker
 
PPTX
Coding Horrors
Mark Baker
 
PPTX
Anonymous classes2
Mark Baker
 
PPTX
Testing the Untestable
Mark Baker
 
PPTX
Anonymous Classes: Behind the Mask
Mark Baker
 
PPTX
Does the SPL still have any relevance in the Brave New World of PHP7?
Mark Baker
 
PPTX
Coding Horrors
Mark Baker
 
PPTX
Does the SPL still have any relevance in the Brave New World of PHP7?
Mark Baker
 
PPTX
Giving birth to an ElePHPant
Mark Baker
 
PPTX
A Functional Guide to Cat Herding with PHP Generators
Mark Baker
 
PPTX
SPL - The Undiscovered Library - PHPBarcelona 2015
Mark Baker
 
PPTX
Zephir - A Wind of Change for writing PHP extensions
Mark Baker
 
Looping the Loop with SPL Iterators
Mark Baker
 
Looping the Loop with SPL Iterators
Mark Baker
 
Deploying Straight to Production
Mark Baker
 
Deploying Straight to Production
Mark Baker
 
Deploying Straight to Production
Mark Baker
 
A Brief History of Elephpants
Mark Baker
 
Aspects of love slideshare
Mark Baker
 
Does the SPL still have any relevance in the Brave New World of PHP7?
Mark Baker
 
A Brief History of ElePHPants
Mark Baker
 
Coding Horrors
Mark Baker
 
Anonymous classes2
Mark Baker
 
Testing the Untestable
Mark Baker
 
Anonymous Classes: Behind the Mask
Mark Baker
 
Does the SPL still have any relevance in the Brave New World of PHP7?
Mark Baker
 
Coding Horrors
Mark Baker
 
Does the SPL still have any relevance in the Brave New World of PHP7?
Mark Baker
 
Giving birth to an ElePHPant
Mark Baker
 
A Functional Guide to Cat Herding with PHP Generators
Mark Baker
 
SPL - The Undiscovered Library - PHPBarcelona 2015
Mark Baker
 
Zephir - A Wind of Change for writing PHP extensions
Mark Baker
 

Recently uploaded (20)

PPTX
Presentation about variables and constant.pptx
kr2589474
 
PDF
Summary Of Odoo 18.1 to 18.4 : The Way For Odoo 19
CandidRoot Solutions Private Limited
 
PPTX
classification of computer and basic part of digital computer
ravisinghrajpurohit3
 
PDF
Salesforce Implementation Services Provider.pdf
VALiNTRY360
 
PDF
Using licensed Data Loss Prevention (DLP) as a strategic proactive data secur...
Q-Advise
 
PPTX
Contractor Management Platform and Software Solution for Compliance
SHEQ Network Limited
 
PDF
49784907924775488180_LRN2959_Data_Pump_23ai.pdf
Abilash868456
 
PDF
Enhancing Healthcare RPM Platforms with Contextual AI Integration
Cadabra Studio
 
PPT
Activate_Methodology_Summary presentatio
annapureddyn
 
PDF
WatchTraderHub - Watch Dealer software with inventory management and multi-ch...
WatchDealer Pavel
 
PDF
vAdobe Premiere Pro 2025 (v25.2.3.004) Crack Pre-Activated Latest
imang66g
 
PDF
Immersive experiences: what Pharo users do!
ESUG
 
PDF
Balancing Resource Capacity and Workloads with OnePlan – Avoid Overloading Te...
OnePlan Solutions
 
PDF
New Download FL Studio Crack Full Version [Latest 2025]
imang66g
 
PPTX
The-Dawn-of-AI-Reshaping-Our-World.pptxx
parthbhanushali307
 
PPTX
AI-Ready Handoff: Auto-Summaries & Draft Emails from MQL to Slack in One Flow
bbedford2
 
PDF
advancepresentationskillshdhdhhdhdhdhhfhf
jasmenrojas249
 
PPTX
Odoo Integration Services by Candidroot Solutions
CandidRoot Solutions Private Limited
 
PPTX
Maximizing Revenue with Marketo Measure: A Deep Dive into Multi-Touch Attribu...
bbedford2
 
PDF
An Experience-Based Look at AI Lead Generation Pricing, Features & B2B Results
Thomas albart
 
Presentation about variables and constant.pptx
kr2589474
 
Summary Of Odoo 18.1 to 18.4 : The Way For Odoo 19
CandidRoot Solutions Private Limited
 
classification of computer and basic part of digital computer
ravisinghrajpurohit3
 
Salesforce Implementation Services Provider.pdf
VALiNTRY360
 
Using licensed Data Loss Prevention (DLP) as a strategic proactive data secur...
Q-Advise
 
Contractor Management Platform and Software Solution for Compliance
SHEQ Network Limited
 
49784907924775488180_LRN2959_Data_Pump_23ai.pdf
Abilash868456
 
Enhancing Healthcare RPM Platforms with Contextual AI Integration
Cadabra Studio
 
Activate_Methodology_Summary presentatio
annapureddyn
 
WatchTraderHub - Watch Dealer software with inventory management and multi-ch...
WatchDealer Pavel
 
vAdobe Premiere Pro 2025 (v25.2.3.004) Crack Pre-Activated Latest
imang66g
 
Immersive experiences: what Pharo users do!
ESUG
 
Balancing Resource Capacity and Workloads with OnePlan – Avoid Overloading Te...
OnePlan Solutions
 
New Download FL Studio Crack Full Version [Latest 2025]
imang66g
 
The-Dawn-of-AI-Reshaping-Our-World.pptxx
parthbhanushali307
 
AI-Ready Handoff: Auto-Summaries & Draft Emails from MQL to Slack in One Flow
bbedford2
 
advancepresentationskillshdhdhhdhdhdhhfhf
jasmenrojas249
 
Odoo Integration Services by Candidroot Solutions
CandidRoot Solutions Private Limited
 
Maximizing Revenue with Marketo Measure: A Deep Dive into Multi-Touch Attribu...
bbedford2
 
An Experience-Based Look at AI Lead Generation Pricing, Features & B2B Results
Thomas albart
 

Electrify your code with PHP Generators

  • 3. PHP Generators Wikipedia defines a Generator as: A generator is very similar to a function that returns an array, in that a generator has parameters, can be called, and generates a sequence of values. However, instead of building an array containing all the values and returning them all at once, a generator yields the values one at a time, which requires less memory and allows the caller to get started processing the first few values immediately. In short, a generator looks like a function but behaves like an iterator.
  • 4. PHP Generators • Introduced in PHP 5.5 • Iterable (Traversable) Objects • Can return a series of values, one at a time • Maintain state between iterations • Can accept values when sent to the generator • Similar to enumerators in Ruby, or Sequence Expressions in F#
  • 5. PHP Generators • Don’t • Add anything to PHP that couldn’t be done before • Do • Allow you to perform iterative operations without an array to iterate • Potentially reduce memory use • Potentially faster than iterating over an array • Can be type-hinted in function/method definitions • Potentially cleaner and shorter code • Add semantics to your code
  • 6. PHP Generators • Automatically created when PHP identifies a function or method containing the “yield” keyword function myGeneration() { yield 1; } $generator = myGeneration(); var_dump($generator); object(Generator)#1 (0) { }
  • 7. PHP Generators • Implemented as an Object final class Generator implements Iterator { mixed current( void ); mixed key( void ); void next( void ); void rewind( void ); mixed send( mixed $value ); mixed throw( Exception $exception ); bool valid( void ); public void __wakeup ( void ) } • Can’t be extended
  • 8. PHP Generators function xrange($lower, $upper) { for ($i = $lower; $i <= $upper; ++$i) { yield $i; } } $rangeGenerator = xrange(0,10); while ($rangeGenerator->valid()) { $key = $rangeGenerator->key(); $value = $rangeGenerator->current(); echo $key , ' -> ' , $value, PHP_EOL; $rangeGenerator->next(); }
  • 9. PHP Generators function xrange($lower, $upper) { for ($i = $lower; $i <= $upper; ++$i) { yield $i; } } foreach (xrange(0,10) as $key => $value) { echo $key , ' -> ' , $value, PHP_EOL; }
  • 10. PHP Generators foreach (range(0,65535) as $i => $value) { echo $i , ' -> ' , $value, PHP_EOL; } function xrange($lower, $upper) { for ($i = $lower; $i <= $upper; ++$i) { yield $i; } } foreach (xrange(0, 65535) as $i => $value) { echo $i , ' -> ' , $value, PHP_EOL; } for($i = 0; $i <= 65535; ++$i) { echo $i , ' -> ' , $value, PHP_EOL; } Time: 0.0183 s Current Memory: 123.44 k Peak Memory: 5500.11 k Time: 0.0135 s Current Memory: 124.33 k Peak Memory: 126.84 k Time: 0.0042 s Current Memory: 122.92 k Peak Memory: 124.49 k
  • 11. PHP Generators function xlColumnRange($lower, $upper) { ++$upper; for ($i = $lower; $i != $upper; ++$i) { yield $i; } } foreach (xlColumnRange('A', 'CQ') as $i => $value) { printf('%3d -> %2s', $i, $value); echo (($i > 0) && ($i+1 % 5 == 0)) ? PHP_EOL : "t"; } 0 -> A 1 -> B 2 -> C 3 -> D 4 -> E 5 -> F 6 -> G 7 -> H 8 -> I 9 -> J 10 -> K 11 -> L 12 -> M 13 -> N 14 -> O 15 -> P 16 -> Q 17 -> R 18 -> S 19 -> T 20 -> U 21 -> V 22 -> W 23 -> X 24 -> Y 25 -> Z 26 -> AA 27 -> AB 28 -> AC 29 -> AD 30 -> AE 31 -> AF 32 -> AG 33 -> AH 34 -> AI 35 -> AJ 36 -> AK 37 -> AL 38 -> AM 39 -> AN 40 -> AO 41 -> AP 42 -> AQ 43 -> AR 44 -> AS 45 -> AT 46 -> AU 47 -> AV 48 -> AW 49 -> AX 50 -> AY 51 -> AZ 52 -> BA 53 -> BB 54 -> BC 55 -> BD 56 -> BE 57 -> BF 58 -> BG 59 -> BH 60 -> BI 61 -> BJ 62 -> BK 63 -> BL 64 -> BM 65 -> BN 66 -> BO 67 -> BP 68 -> BQ 69 -> BR 70 -> BS 71 -> BT 72 -> BU 73 -> BV 74 -> BW 75 -> BX 76 -> BY 77 -> BZ 78 -> CA 79 -> CB 80 -> CC 81 -> CD 82 -> CE 83 -> CF 84 -> CG 85 -> CH 86 -> CI 87 -> CJ 88 -> CK 89 -> CL 90 -> CM 91 -> CN 92 -> CO 93 -> CP 94 -> CQ
  • 12. PHP Generators $isEven = function ($value) { return !($value & 1); }; $isOdd = function ($value) { return $value & 1; }; function xFilter(callable $callback, array $args=array()) { foreach ($args as $arg) if (call_user_func($callback, $arg)) yield $arg; }
  • 13. PHP Generators $data = range(1,10); echo 'xFilter for Odd Numbers', PHP_EOL; foreach (xFilter($isOdd, $data) as $i) echo('num is: '.$i.PHP_EOL); echo 'xFilter for Even Numbers', PHP_EOL; foreach (xFilter($isEven, $data) as $i) echo('num is: '.$i.PHP_EOL); xFilter for Odd Numbers num is: 1 num is: 3 num is: 5 num is: 7 num is: 9 xFilter for Even Numbers num is: 2 num is: 4 num is: 6 num is: 8 num is: 10
  • 14. PHP Generators • Can return both a value and a “pseudo” key • By default • The key is an integer value • Starting with 0 for the first iteration • Incrementing by 1 each iteration • Accessed from foreach() as: foreach(generator() as $key => $value) {} • or using $key = $generatorObject->key();
  • 15. PHP Generators • Default key behaviour can be changed • Syntax is: yield $key => $value; • Unlike array keys: • “Pseudo” keys can be any PHP datatype • “Pseudo” key values can be duplicated
  • 16. PHP Generators function xrange($lower, $upper) { $k = $upper; for ($i = $lower; $i <= $upper; ++$i) { yield $k-- => $i; } } foreach (xrange(0, 8) as $i => $value) { echo $i, ' -> ', $value, PHP_EOL; } 8 -> 0 7 -> 1 6 -> 2 5 -> 3 4 -> 4 3 -> 5 2 -> 6 1 -> 7 0 -> 8
  • 17. PHP Generators function duplicateKeys($lower, $upper) { for ($i = $lower; $i <= $upper; ++$i) { yield (($i-1) % 3) + 1 => $i; } } foreach (duplicateKeys(1,15) as $i => $value){ echo $i , ' -> ' , $value, PHP_EOL; } 1 -> 1 2 -> 2 3 -> 3 1 -> 4 2 -> 5 3 -> 6 1 -> 7 2 -> 8 3 -> 9 1 -> 10 2 -> 11 3 -> 12 1 -> 13 2 -> 14 3 -> 15
  • 18. PHP Generators function duplicateKeys($string) { $string = strtolower($string); $length = strlen($string); for ($i = 0; $i < $length; ++$i) { yield strtoupper($string[$i]) => $string[$i]; } } foreach (duplicateKeys('badass') as $key => $value) { echo $key , ' -> ' , $value, PHP_EOL; } B -> b A -> a D -> d A -> a S -> s S -> s
  • 19. PHP Generators function floatKeys($lower, $upper) { for ($i = $lower; $i <= $upper; ++$i) { yield ($i / 5) => $i; } } foreach (floatKeys(1,16) as $i => $value) { printf( '%0.2f -> %2d' . PHP_EOL, $i, $value ); } 0.20 -> 1 0.40 -> 2 0.60 -> 3 0.80 -> 4 1.00 -> 5 1.20 -> 6 1.40 -> 7 1.60 -> 8 1.80 -> 9 2.00 -> 10 2.20 -> 11 2.40 -> 12 2.60 -> 13 2.80 -> 14 3.00 -> 15 3.20 -> 16
  • 20. PHP Generators • It is possible to access generated values “by reference” • The generator must be declared “by reference” • The yielded value must be a variable, and cannot be an expression
  • 21. PHP Generators function &byReference2($size) { for($val=1, $key=1; $key <= $size; ++$val, ++$key) { yield $key => $val; } } $size = 10; foreach (byReference2($size) as $key => &$value) { echo $key, ' => ', $value, ' => ', ($value += $value - 1), PHP_EOL; } echo PHP_EOL; 1 => 1 => 1 2 => 2 => 3 3 => 4 => 7 4 => 8 => 15 5 => 16 => 31 6 => 32 => 63 7 => 64 => 127 8 => 128 => 255 9 => 256 => 511 10 => 512 => 1023
  • 22. PHP Generators • Data can be passed to the generator • Sometimes called a “Coroutine” when used in this way • Not strictly accurate, they are more strictly a “Semicoroutine” • They can form the basis for a “Coroutine” with the addition of a top-level dispatcher routine • Syntax is: $value = yield; • Calling script uses the “send()” method: $generatorObject->send($value);
  • 23. PHP Generators $data = array( 'Squirtle', 'Jigglypuff', 'Charmander', 'Bulbasaur', 'White DPC Elephpant', ); function generatorSend() { while (true) { $cityName = yield; echo $cityName, PHP_EOL; } } $generatorObject = generatorSend(); foreach($data as $value) { $generatorObject->send($value); } echo PHP_EOL, 'Gotta Collect 'em all', PHP_EOL; Squirtle Jigglypuff Charmander Bulbasaur White DPC Elephpant Gotta Collect 'em All
  • 24. PHP Generators $logFileName = __DIR__ . '/error.log'; function logger($logFileName) { $f = fopen($logFileName, 'a'); while ($logentry = yield) { fwrite( $f, (new DateTime())->format('Y-m-d H:i:s ') . $logentry . PHP_EOL ); } } $logger = logger($logFileName); for($i = 0; $i < 12; ++$i) { $logger->send('Message #' . $i ); }
  • 25. PHP Generators • It is possible to combine a Generator to both send and accept data
  • 26. PHP Generators function generatorSend($limit) { for ($i = 1; $i <= $limit; ++$i) { yield $i => pow($i, $i); $continue = yield; if (!$continue) break; } } $generatorObject = generatorSend(100); while ($generatorObject->valid()) { $key = $generatorObject->key(); $value = $generatorObject->current(); $generatorObject->next(); $generatorObject->send($key >= 10); echo $key, ' -> ', $value, PHP_EOL; } 1 -> 1 2 -> 4 3 -> 27 4 -> 256 5 -> 3125 6 -> 46656 7 -> 823543 8 -> 16777216 9 -> 387420489 10 -> 10000000000
  • 27. PHP Generators (Gotcha) function generatorSend($limit) { for ($i = 1; $i <= $limit; ++$i) { yield pow($i, $i); $continue = yield; if (!$continue) break; } } $generatorObject = generatorSend(100); while ($generatorObject->valid()) { $key = $generatorObject->key(); $value = $generatorObject->current(); $generatorObject->next(); $generatorObject->send($key >= 10); echo $key, ' -> ', $value, PHP_EOL; } 0 -> 1 2 -> 4 4 -> 27 6 -> 256 8 -> 3125 10 -> 46656
  • 28. PHP Generators function generatorSend($limit) { for ($i = 1; $i <= $limit; ++$i) { $continue = (yield pow($i, $i)); if (!$continue) break; } } $generatorObject = generatorSend(100); while($generatorObject->valid()) { $key = $generatorObject->key(); $value = $generatorObject->current(); echo $key, ' -> ', $value, PHP_EOL; $generatorObject->send($key >= 10); } 0 -> 1 1 -> 4 2 -> 27 3 -> 256 4 -> 3125 5 -> 46656 6 -> 823543 7 -> 16777216 8 -> 387420489 9 -> 10000000000
  • 29. PHP Generators (Gotcha) function generatorSend($limit) { for ($i = 1; $i <= $limit; ++$i) { $continue = (yield pow($i, $i)); if (!$continue) break; } } $generatorObject = generatorSend(100); foreach($generatorObject as $key => $value) { echo $key, ' -> ', $value, PHP_EOL; $generatorObject->send($key >= 10); } 0 -> 1
  • 30. PHP Generators (Gotcha) function generatorSend($limit) { for ($i = 1; $i <= $limit; ++$i) { $continue = (yield pow($i, $i)); if (!$continue && $continue !== null) break; } } $generatorObject = generatorSend(100); foreach($generatorObject as $key => $value) { echo $key, ' -> ', $value, PHP_EOL; $generatorObject->send($key >= 10); } 1 -> 1 3 -> 27 5 -> 3125 7 -> 823543 9 -> 387420489 11 -> 285311670611
  • 31. PHP Generators (Gotcha) function generatorSend($limit) { for ($i = 1; $i <= $limit; ++$i) { $continue = (yield pow($i, $i)); if (!$continue && $continue !== null) break; elseif (!$continue && $continue === null) --$i; } } $generatorObject = generatorSend(100); foreach($generatorObject as $key => $value) { echo $key, ' -> ', $value, PHP_EOL; $generatorObject->send($key >= 10); } 1 -> 1 2 -> 4 3 -> 27 4 -> 256 5 -> 3125 6 -> 46656 7 -> 823543 8 -> 16777216 9 -> 387420489 10 -> 10000000000
  • 32. PHP Generators • By sending data into a Generator it is possible to change its behaviour
  • 33. PHP Generators function diamond($size) { $i = $key = 1; do { $ascending = (yield $key => str_repeat(' ', $size - $i) . str_repeat('*', $i*2-1) . str_repeat(' ', $size - $i)); if ($ascending !== null) { ($ascending) ? ++$i : --$i; ++$key; } } while($i > 0); } $size = 5; $diamond = diamond($size); foreach ($diamond as $key => $value) { echo sprintf('%2d', $key), ' => ', $value, PHP_EOL; $diamond->send($key < $size); } 1 => * 2 => *** 3 => ***** 4 => ******* 5 => ********* 6 => ******* 7 => ***** 8 => *** 9 => *
  • 34. PHP Generators function adjustableIncrementor($value = 1, $increment = 1) { do { $increment = (yield $value); $value += $increment; } while ($value <= PHP_INT_MAX); } $incrementor = adjustableIncrementor(); foreach ($incrementor as $increment) { echo number_format($increment), PHP_EOL; $incrementor->send($increment); } 1 2 4 8 16 32 64 128 256 512 1,024 ... 268,435,456 536,870,912 1,073,741,824
  • 35. PHP Generators function adjustableIncrementor($value = 1, $increment = 1) { do { $increment = (yield $value); $value += $increment; } while ($value <= PHP_INT_MAX); } $incrementor = adjustableIncrementor(); foreach ($incrementor as $increment) { echo number_format($increment), PHP_EOL; $incrementor->send(pow(10, strlen($increment)-1)); } 1 2 3 ... 9 10 20 30 ... 90 100 200 300 ... 900 1,000 ...
  • 36. PHP Generators • We can also throw an Exception into a Generator • A Try/Catch block should be defined in the Generator • We use the Generator’s “throw()” method from the calling code $generatorObject->throw(new Exception(‘xyz’)); • Useful for terminating a Generator loop if we don’t want to code a send() in every iteration
  • 37. PHP Generators function filteredNumbers(Callable $filter) { $i = 1; try { do { if (call_user_func($filter, $i)) { yield $i; } } while ($i++ <= PHP_INT_MAX); } catch (Exception $e) { echo $e->getMessage(), PHP_EOL; } }
  • 38. PHP Generators $primes = filteredNumbers($isPrime); foreach ($primes as $counter => $prime) { if ($prime > 50) { $primes->throw( new Exception('Enough already') ); continue; } echo $prime, PHP_EOL; } 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 Enough already
  • 39. PHP Generators • You can’t pass Generators as arguments to array functions So you can’t call array_map() or array_reduce()with a Generator instead of an array argument • But by passing a Generator as an argument to another Generator, we can chain Generators Allowing us to simulate array_map() or array_reduce()
  • 40. PHP Generators function filteredNumbers(Callable $filter) { $i = 1; do { if (call_user_func($filter, $i)) { yield $i; } } while ($i++ <= PHP_INT_MAX); }
  • 41. PHP Generators function filteredValueLimit(Traversable $filter, $limit) { foreach ($filter as $value) { if ($value > $limit) { break; } yield $value; } }
  • 42. PHP Generators function mappedFilterList(Traversable $filter, Callable $callback) { foreach ($filter as $value) { yield $value => call_user_func($callback, $value); } }
  • 43. PHP Generators $primes = filteredNumbers($isPrime); $primes64 = filteredValueLimit($primes, 64); $primesSquared = mappedFilterList( $primes64, function($value) { return $value * $value; } ); foreach ($primesSquared as $primeSquared) { echo $prime, ' => ', $primeSquared, PHP_EOL; } 2 => 4 3 => 9 5 => 25 7 => 49 11 => 121 13 => 169 17 => 289 19 => 361 23 => 529 29 => 841 31 => 961 37 => 1369 41 => 1681 43 => 1849 47 => 2209 53 => 2809 59 => 3481 61 => 3721
  • 44. PHP Generators function reduceFilterList(Traversable $filter, Callable $callback, $initial) { $result = $initial; foreach($filter as $value) { $result = call_user_func($callback, $value, $result); } yield $result; }
  • 45. PHP Generators $primes = filteredNumbers2($isPrime); $primes64 = filteredValueLimit($primes, 64); $sumPrimes = reduceFilterList( $primes64, function($value, $initial) { return $value + $initial; }, 0 ); $sumPrime = $sumPrimes->current(); echo $sumPrime, PHP_EOL; 501
  • 46. PHP Generators • Limitations • Can’t be Extended • Can’t be Serialized • Can’t be “Rewound”
  • 47. PHP Generators • Additional Reading: • http://blog.ircmaxell.com/2012/07/what-generators-can-do-for-you.html • http://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html • https://markbakeruk.net/2016/01/19/a-functional-guide-to-cat-herding-with-php- generators/
  • 48. Electrify your code with PHP Generators ? Questions
  • 49. Who am I? Mark Baker Design and Development Manager InnovEd (Innovative Solutions for Education) Learning Ltd Coordinator and Developer of: Open Source PHPOffice library PHPExcel, PHPWord, PHPPowerPoint, PHPProject, PHPVisio Minor contributor to PHP core 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