Slide 1

Slide 1 text

It Feels Great to Iterate By Jeremy Lindblom • @jeremeamia ( see also: @seaphp • @awsforphp • @phpbard )

Slide 2

Slide 2 text

WARNING This is not a talk about agile development, but, yes, “iterate” is a somewhat overloaded term, so I can see how you might have been confused.

Slide 3

Slide 3 text

This talk is about

Slide 4

Slide 4 text

Actually, we'll be covering a lot of OOP

Slide 5

Slide 5 text

———————— ★ Iterators ★ ———————— ★ Decorators ★ ———————— ★ Generators ★ ————————

Slide 6

Slide 6 text

Q. Why is PHP so friggin' awesome?

Slide 7

Slide 7 text

array()  

Slide 8

Slide 8 text

[]   ( Since PHP 5.4 )

Slide 9

Slide 9 text

Is it a(n)… a.  List b.  Map c.  Vector d.  Queue e.  Stack []  

Slide 10

Slide 10 text

Is it a(n)… a.  List b.  Map c.  Vector d.  Queue e.  Stack f.  All of the above []  

Slide 11

Slide 11 text

array_column(…);   array_diff(…);   array_filter(…);   array_keys(…);   array_map(…);   array_merge(…);   array_push(…);   array_slice(…);   array_unshift(…);  

Slide 12

Slide 12 text

$speaker  =  [      'name'          =>  'Jeremy  Lindblom',      'twitter'    =>  '@jeremeamia',      'employer'  =>  'AWS  (Amazon)',      'bio'            =>  [          'Works  on  AWS  SDK  for  PHP',          'Is  president  of  @SeaPHP',          'Is  PHP-­‐FIG  rep  for  Guzzle',          'Writes  PHPoetry  as  @phpbard',      ]   ];  

Slide 13

Slide 13 text

foreach  ($data  as  $item)  {          echo  $item  .  "\n";   }   Iterating arrays

Slide 14

Slide 14 text

foreach  ($data  as  $key  =>  $value)  {        echo  $key  .  ':'  .  $value  .  "\n";   }   Iterating arrays (w/ keys)

Slide 15

Slide 15 text

$data  =  new  DirectoryIterator(__DIR__);   foreach  ($data  as  $file)  {          echo  $file-­‐>getFilename()  .  "\n";   }   Iterating objects?

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

$data  =  new  DirectoryIterator(__DIR__);   foreach  ($data  as  $file)  {          echo  $file-­‐>getFilename()  .  "\n";   }   Iterating objects?

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

AppendIterator ArrayIterator CachingIterator CallbackFilterIterator DirectoryIterator EmptyIterator FilesystemIterator FilterIterator GlobIterator InfiniteIterator Iterator IteratorAggregate IteratorIterator LimitIterator MultipleIterator NoRewindIterator OuterIterator ParentIterator RecursiveArrayIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIteratorIterator RecursiveTreeIterator RegexIterator SimpleXMLIterator SplFileObject SplQueue SplStack

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

•  Iterator •  Iterate / Traverse / "foreach over" •  Iterable / Traversable •  Iteration •  Emit / Yield Quick Terms

Slide 22

Slide 22 text

if  ($object  instanceof  Traversable)  {          echo  "It  can  be  used  in  a  foreach.";   }   Traversable objects

Slide 23

Slide 23 text

TIP #1 You can tell if a value is foreach-able by checking if it is an array or an instance of Traversable.

Slide 24

Slide 24 text

class  Foo  implements  Traversable  {          …   }   Implement Traversable?

Slide 25

Slide 25 text

class  Foo  implements  Traversable  {          …   }   >  PHP  Fatal  error:  Class  Foo  must     >  implement  interface  Traversable  as     >  part  of  either  Iterator  or   >  IteratorAggregate.   Implement Traversable? NOPE!

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

  Traversable     Iterator     IteratorAggregate  

Slide 28

Slide 28 text

interface  Iterator  {        function  current();  //  mixed|false        function  key();          //  scalar|null        function  next();        //  void        function  rewind();    //  void        function  valid();      //  bool   }   Iterator Interface

Slide 29

Slide 29 text

foreach  ($iterator  as  $key  =>  $value)  {          //  Do  stuff!   }  

Slide 30

Slide 30 text

foreach  ($iterator  as  $key  =>  $value)  {          //  Do  stuff!   }     //  THIS  IS  THE  SAME  AS:     $iterator-­‐>rewind();   while  ($iterator-­‐>valid())  {          $key  =  $iterator-­‐>key();          $value  =  $iterator-­‐>current();          //  Do  stuff!          $iterator-­‐>next();   }  

Slide 31

Slide 31 text

TIP #2 foreach automatically performs a rewind on the iterator. Other loops do not.

Slide 32

Slide 32 text

TIP #3 Most iterators must be rewound before they work properly.

Slide 33

Slide 33 text

$numbers  =  new  HundoIterator();   foreach  ($numbers  as  $number)  {          echo  $number  .  "\n";   }     >  1   >  2   >  …   >  99   >  100   Example Implementation

Slide 34

Slide 34 text

class  HundoIterator  implements  Iterator  {      private  $num  =  1;      function  current()  {            return  $this-­‐>valid()  ?  $this-­‐>num  :  false;      }      function  key()  {          return  $this-­‐>valid()  ?  $this-­‐>num  –  1  :  null;      }      function  next()  {$this-­‐>num++;}      function  rewind()  {$this-­‐>num  =  1;}      function  valid()  {return  $this-­‐>num  <=  100;}   }   Example Implementation

Slide 35

Slide 35 text

TIP #4 To avoid bugs, you should make your Iterator's methods “idempotent” per iteration.

Slide 36

Slide 36 text

class  HundoIterator  implements  Iterator  {      private  $num  =  1;      function  current()  {            return  $this-­‐>valid()  ?  $this-­‐>num  :  false;      }      function  key()  {          return  $this-­‐>valid()  ?  $this-­‐>num  –  1  :  null;      }      function  next()  {$this-­‐>num++;}      function  rewind()  {$this-­‐>num  =  1;}      function  valid()  {return  $this-­‐>num  <=  100;}   }   Idempotency?

Slide 37

Slide 37 text

$numbers  =  new  HundoIterator();   foreach  ($numbers  as  $number)  {          echo  $number  .  "\n";   }     >  1   >  2   >  …   >  99   >  100   Example Implementation

Slide 38

Slide 38 text

COOL!

Slide 39

Slide 39 text

WAIT!

Slide 40

Slide 40 text

WHY?

Slide 41

Slide 41 text

Because… OOP?

Slide 42

Slide 42 text

No, give me real reasons.

Slide 43

Slide 43 text

OK… Fine!

Slide 44

Slide 44 text

$numbers  =  range(1,  100);   foreach  ($numbers  as  $number)  {          echo  $number  .  "\n";   }     >  1   >  2   >  …   >  99   >  100   Array Implementation

Slide 45

Slide 45 text

$numbers  =  range(1,  100);   foreach  ($numbers  as  $number)  {          echo  $number  .  "\n";   }     >  1   >  2   >  …   >  99   >  100   Array Implementation Yeah! See…?

Slide 46

Slide 46 text

$numbers  =  range(1,  100);   foreach  ($numbers  as  $number)  {          echo  $number  .  "\n";   }     >  1   >  2   >  …   >  99   >  100   Array Implementation Wait for it…

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

$numbers  =  range(1,  1000000000);   foreach  ($numbers  as  $number)  {          echo  $number  .  "\n";   }   When arrays don't work

Slide 49

Slide 49 text

$numbers  =  range(1,  1000000000);   foreach  ($numbers  as  $number)  {          echo  $number  .  "\n";   }     >  PHP  Fatal  error:    Allowed  memory   >  size  of  536870912  bytes  exhausted   When arrays don't work Oh noes!

Slide 50

Slide 50 text

$numbers  =  range(1,  1000000000);   foreach  ($numbers  as  $number)  {          echo  $number  .  "\n";   }     >  PHP  Fatal  error:    Allowed  memory   >  size  of  536870912  bytes  exhausted   When arrays don't work Inorite?

Slide 51

Slide 51 text

class  RangeIterator  implements  Iterator  {      private  $value  =  1;      private  $limit;      function  __construct($limit)  {          $this-­‐>limit  =  $limit;      }      //  ...      function  valid()  {          return  ($this-­‐>value  <=  $this-­‐>limit);      }   }   Will iterators work?

Slide 52

Slide 52 text

$numbers  =  new  RangeIterator(1000000000);   foreach  ($numbers  as  $number)  {          echo  $number  .  "\n";   }     >  1   >  2   >  …   >  999999999   >  1000000000   Will iterators work?

Slide 53

Slide 53 text

$numbers  =  new  RangeIterator(1000000000);   foreach  ($numbers  as  $number)  {          echo  $number  .  "\n";   }     >  1   >  2   >  …   >  999999999   >  1000000000   Will iterators work? Ah, I see.

Slide 54

Slide 54 text

$numbers  =  new  RangeIterator(1000000000);   foreach  ($numbers  as  $number)  {          echo  $number  .  "\n";   }     >  1   >  2   >  …   >  999999999   >  1000000000   Will iterators work? Yep. Told ya.

Slide 55

Slide 55 text

Why Iterators? 1.  Reduced memory ✓

Slide 56

Slide 56 text

Why Iterators? 1.  Reduced memory ✓ 2.  Encapsulation 3.  Lazy evaluation 4.  Composition

Slide 57

Slide 57 text

Encapsulation[0]
             
  • =  $note-­‐>getMessage()  ?>
  •    
 

Slide 58

Slide 58 text

Encapsulation[1] $sql  =  'SELECT  *  FROM  notes';   $stmt  =  $pdo-­‐>prepare($sql);   $stmt-­‐>execute();     $notes  =  $stmt-­‐>fetchAll();  

Slide 59

Slide 59 text

Encapsulation[1] $sql  =  'SELECT  *  FROM  notes';   $stmt  =  $pdo-­‐>prepare($sql);   $stmt-­‐>execute();     $notes  =  $stmt-­‐>fetchAll();   •  Loads all results into memory. •  Hard to transform data.

Slide 60

Slide 60 text

Encapsulation[2] $sql  =  'SELECT  *  FROM  notes';   $stmt  =  $pdo-­‐>prepare($sql);   $stmt-­‐>execute();     $notes  =  [];   while  ($row  =  $stmt-­‐>fetch())  {    $notes[]  =  new  Note($row);   }  

Slide 61

Slide 61 text

Encapsulation[2] $sql  =  'SELECT  *  FROM  notes';   $stmt  =  $pdo-­‐>prepare($sql);   $stmt-­‐>execute();     $notes  =  [];   while  ($row  =  $stmt-­‐>fetch())  {    $notes[]  =  new  Note($row);   }   •  Loads all results into memory. •  Easy to transform data.

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

Encapsulation[3] $sql  =  'SELECT  *  FROM  notes';   $stmt  =  $pdo-­‐>prepare($sql);   $stmt-­‐>execute();     $notes  =  [];   foreach  ($stmt  as  $row)  {    $notes[]  =  new  Note($row);   }   •  Loads all results into memory. •  Easy to transform data.

Slide 64

Slide 64 text

Encapsulation[4] class  NoteIterator  extends  IteratorIterator  {          public  function  current()  {                  return  new  Note(parent::current());          }   }  

Slide 65

Slide 65 text

TIP #5 Be lazy. Delay doing anything with data until you absolutely need to. Iterators help with this.

Slide 66

Slide 66 text

Encapsulation[5] $sql  =  'SELECT  *  FROM  notes';   $stmt  =  $pdo-­‐>prepare($sql);   $stmt-­‐>execute();     $notes  =  new  NoteIterator($stmt);   •  Uses memory wisely. •  Easy to transform data. •  Encapsulates logic. •  Notes created lazily.  

Slide 67

Slide 67 text

Why Iterators? 1.  Reduced memory ✓ 2.  Encapsulation ✓ 3.  Lazy evaluation ✓ 4.  Composition

Slide 68

Slide 68 text

Why Iterators? 1.  Reduced memory ✓ 2.  Encapsulation ✓ 3.  Lazy evaluation ✓ 4.  Composition ✓

Slide 69

Slide 69 text

Composition When one object contains another object, combining their behaviors.

Slide 70

Slide 70 text

Composition $notes  =  new  NoteIterator($stmt);   PDOStatement   (Traversable)   We "wrapped" one iterator with another, composing their behaviors together.

Slide 71

Slide 71 text

AppendIterator ArrayIterator CachingIterator CallbackFilterIterator DirectoryIterator EmptyIterator FilesystemIterator FilterIterator GlobIterator InfiniteIterator Iterator IteratorAggregate IteratorIterator LimitIterator MultipleIterator NoRewindIterator OuterIterator ParentIterator RecursiveArrayIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIteratorIterator RecursiveTreeIterator RegexIterator SimpleXMLIterator SplFileObject SplQueue SplStack

Slide 72

Slide 72 text

And now a poem about Decorators, by the @phpbard

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

  Component   Component   ComponentDecorator    

Slide 75

Slide 75 text

Foo  extends  Bar  

Slide 76

Slide 76 text

$nums  =  new  RangeIterator(100);   foreach  ($nums  as  $num)  {          echo  $num  .  "\n";   }     >  1   >  2   >  …   >  99   >  100   Iterators

Slide 77

Slide 77 text

interface  Iterator  {        function  current();  //  mixed|false        function  key();          //  scalar|null        function  next();        //  void        function  rewind();    //  void        function  valid();      //  bool   }   Iterators

Slide 78

Slide 78 text

LimitIterator   $nums  =  new  RangeIterator(100);   $nums  =  new  LimitIterator($nums,  10,  5);   foreach  ($nums  as  $num)  {          echo  $num  .  "\n";   }     >  10   >  11   >  12   >  13   >  14  

Slide 79

Slide 79 text

CallbackFilterIterator   $nums  =  new  RangeIterator(100);   $nums  =  new  CallbackFilterIterator($nums,          function  ($n)  {return  $n  %  5  ===  0;}   );   foreach  ($nums  as  $num)  {          echo  $num  .  "\n";   }   >  5   >  10   >  …   >  95   >  100  

Slide 80

Slide 80 text

LimitIterator   CallbackFilterItr     Iterator   OurCoolIterator  

Slide 81

Slide 81 text

LimitIterator   CallbackFilterItr     Iterator   OurCoolIterator   ?

Slide 82

Slide 82 text

LimitIterator   CallbackFilterItr     Iterator   OurCoolIterator   x  

Slide 83

Slide 83 text

Decorate! $nums  =  new  RangeIterator(100);     $nums  =  new  CallbackFilterIterator($nums,          function  ($n)  {return  $n  %  5  ===  0;}   );     $nums  =  new  LimitIterator($nums,  10,  5);  

Slide 84

Slide 84 text

Decorate! foreach  ($nums  as  $num)  {          echo  $num  .  "\n";   }     >  10   >  15   >  20   >  25   >  30  

Slide 85

Slide 85 text

LimitIterator   CallbackFilterIterator   RangeIterator     current()   current()   current()  

Slide 86

Slide 86 text

Thank you! @phpbard phpbard.tumblr.com

Slide 87

Slide 87 text

TIP #6 Use composition of iterators instead of implementing new classes when possible.

Slide 88

Slide 88 text

Generators $stmt-­‐>execute();     $getNotes  =  function  ($stmt)  {        foreach  ($stmt  as  $row)  {              yield  new  Note($row);        }   };     $notes  =  $getNotes($stmt);  

Slide 89

Slide 89 text

TIP #7 Read the Manual.

Slide 90

Slide 90 text

It Feels Great to Iterate By Jeremy Lindblom • @jeremeamia ( see also: @seaphp • @awsforphp • @phpbard )

Slide 91

Slide 91 text

Vocabulary •  Iterator •  Traversable •  Interface •  Encapsulation •  Composition •  Decorator •  Generator •  Adapter •  Idempotent •  SOLID •  Inheritance •  Proxy