Upgrade to Pro — share decks privately, control downloads, hide ads and more …

(Re)discovering the SPL - Sweetlake 14

Joshua Thijssen
September 05, 2014
48

(Re)discovering the SPL - Sweetlake 14

Joshua Thijssen

September 05, 2014
Tweet

Transcript

  1. 2 Joshua Thijssen Freelance consultant and trainer @ TechAdemy Founder

    of TechAnalyze.io Founder of the Dutch Web Alliance Blog: http://adayinthelifeof.nl Email: [email protected] Twitter: @jaytaph
  2. 6

  3. 6

  4. 7

  5. 8

  6. ➡ Interfaces ➡ Iterators ➡ Data structures ➡ Exceptions ➡

    Miscellaneous functionality 9 Every SPL talk available:
  7. 13

  8. ➡ Traversable cannot be implemented. ➡ Traversable can be detected

    (instanceof). ➡ foreach() detects traversable interfaces and does magic things. 13
  9. Iterator extends Traversable { /* Methods */ abstract public mixed

    current ( void ) abstract public scalar key ( void ) abstract public void next ( void ) abstract public void rewind ( void ) abstract public boolean valid ( void ) } 16 Iterator interface:
  10. 17

  11. 18 1 <?php 2 3 $bookCollection = array( 4 new

    Book("50 shades of gray"), 5 new Book("The Hobbit"), 6 new Book("It"), 7 array( 8 new Book("Discworld: The colour of magic"), 9 new Book("Discworld: A light fantastic"), 10 ), 11 array( 12 new Book("Harry Potter and the deadly hallows"), 13 /* ... */ 14 ), 15 /* ... */ 16 ); 17 18 foreach ($bookCollection as $book) { 19 // Do something with a book, but how about book-series? 20 }
  12. 19 1 <?php 2 3 $bookCollection = new BookCollection( 4

    array( 5 new Book("50 shades of gray"), 6 new Book("The Hobbit"), 7 new Book("It"), 8 array('Discworld' => 9 new Book("The colour of magic"), 10 new Book("A light fantastic"), 11 ), 12 array('Harry Potter' => 13 new Book("Harry Potter and the deadly hallows"), 14 /* ... */ 15 ), 16 /* ... */ 17 )); 18 19 foreach ($bookCollection as $book) { 20 // Do something with all single books 21 } 22 23 foreach ($bookCollection->getSeries('Harry Potter')) { 24 // Do something with just one serie 25 } 26 27 $it = $bookCollection->getTopRatedBooks(); 28 $it2 = new LimitIterator($it, 0, 5); 29 foreach ($it2 as $book) { 30 // Do something with the top 5 31 } 32 33 $it = $bookCollection->getTopRatedBooks(); 34 $it2 = new RegexIterator($it, '/(gray|colour)/'); 35 foreach ($it2 as $book) { 36 // Do something with all books that have 'gray' or 'colour' in the title 37 }
  13. 1 $dir = opendir("."); 2 while (($file = readdir($dir)) !==

    false) { 3 4 # Business logic happens here 5 print "file: $file\n"; 6 7 } 20
  14. 1 $dir = opendir("."); 2 while (($file = readdir($dir)) !==

    false) { 3 4 # hack: filter only mp3 files 5 if (! preg_match('|\.mp3$|i', $file)) { 6 continue; 7 } 8 9 # Business logic happens here 10 print "file: $file\n"; 11 } 21
  15. ➡ Filter all MP3 and all JPG files. ➡ Filter

    all MP3 files that are larger than 6MB. 22
  16. ➡ Filter all MP3 and all JPG files. ➡ Filter

    all MP3 files that are larger than 6MB. ➡ Do not filter at all. 22
  17. ➡ Filter all MP3 and all JPG files. ➡ Filter

    all MP3 files that are larger than 6MB. ➡ Do not filter at all. ➡ Search sub-directories as well. 22
  18. ➡ Filter all MP3 and all JPG files. ➡ Filter

    all MP3 files that are larger than 6MB. ➡ Do not filter at all. ➡ Search sub-directories as well. ➡ Search multiple directories. 22
  19. 23

  20. ➡ How to test? (we can’t) ➡ How to maintain?

    (we can’t) ➡ How to reuse? (we can’t) 23
  21. 1 $it = new DirectoryIterator("."); 2 foreach ($it as $fi)

    { 3 print "File: ".$fi->getPathname()."\n"; 4 } 24
  22. 1 $it = new DirectoryIterator("."); 2 $it2 = new RegexIterator($it,

    "/\.mp3$/i"); 3 foreach ($it2 as $fi) { 4 print "File: ".$fi->getPathname()."\n"; 5 } 25
  23. 1 $it = new DirectoryIterator("."); 2 $it2 = new RegexIterator($it,

    "/\.mp3$/i"); 3 $it3 = new FilesizeIterator($it2, 0, 6 * 1024 * 1024); 4 $it4 = new LimitIterator($it3, 10, 5); 5 6 foreach ($it4 as $fi) { 7 print "File: ".$fi->getPathname()."\n"; 8 } 26
  24. 1 $it = new DirectoryIterator("."); 2 $it2 = new RegexIterator($it,

    "/\.mp3$/i"); 3 $it3 = new FilesizeIterator($it2, 0, 6 * 1024 * 1024); 4 $it4 = new LimitIterator($it3, 10, 5); 5 6 foreach ($it4 as $fi) { 7 print "File: ".$fi->getPathname()."\n"; 8 } 26
  25. 27

  26. ✓ Reusable We can use iterators where ever we want.

    ✓ Testable Iterators can be tested separately. 27
  27. ✓ Reusable We can use iterators where ever we want.

    ✓ Testable Iterators can be tested separately. ✓ Maintainable No need to adapt our business logic. 27
  28. 1 class myIterator implements \Iterator { 2 /* ... */

    3 } 4 5 $a = array(1, 2, 3); 6 $it = new myIterator($a); 7 8 print count($it); 29
  29. 1 class myIterator implements \Iterator { 2 /* ... */

    3 } 4 5 $a = array(1, 2, 3); 6 $it = new myIterator($a); 7 8 print count($it); 1 29
  30. 1 class myCountableIterator extends myIterator implements Countable { 2 function

    count() { 3 return count($this->_elements); 4 } 5 } 6 7 $a = array(1, 2, 3, 4, 5); 8 $it = new myCountableIterator($a); 9 10 print count($it); 30
  31. 1 class myCountableIterator extends myIterator implements Countable { 2 function

    count() { 3 return count($this->_elements); 4 } 5 } 6 7 $a = array(1, 2, 3, 4, 5); 8 $it = new myCountableIterator($a); 9 10 print count($it); 5 30
  32. 1 class myCountableIterator extends myIterator implements Countable { 2 function

    count() { 3 return count($this->_arr); 4 } 5 } 6 7 $a = array(1, 2, 3, 4, 5); 8 $it = new myCountableIterator($a); 9 $it2 = new limitIterator($it, 0, 3); 10 11 print count($it2); 31
  33. 1 class myCountableIterator extends myIterator implements Countable { 2 function

    count() { 3 return count($this->_arr); 4 } 5 } 6 7 $a = array(1, 2, 3, 4, 5); 8 $it = new myCountableIterator($a); 9 $it2 = new limitIterator($it, 0, 3); 10 11 print count($it2); 1 31
  34. SPL Iterators ➡ AppendIterator ➡ ArrayIterator ➡ CachingIterator ➡ CallbackFilterIterator

    ➡ DirectoryIterator ➡ EmptyIterator ➡ FilesystemIterator ➡ FilterIterator ➡ GlobIterator ➡ InfiniteIterator ➡ IteratorIterator ➡ LimitIterator ➡ MultipleIterator ➡ NoRewindIterator ➡ ParentIterator ➡ RecursiveArrayIterator ➡ RecursiveCachingIterator ➡ RecursiveCallbackFilterIterator ➡ RecursiveDirectoryIterator ➡ RecursiveFilterIterator ➡ RecursiveIteratorIterator ➡ RecursiveRegexIterator ➡ RecursiveTreeIterator ➡ RegexIterator ➡ SimpleXMLIterator 33
  35. 35

  36. 36

  37. 39 1 $it = new myIterator(); 2 if ($it instanceof

    \IteratorAggregate) { 3 $it = $it->getIterator(); 4 } 5 $it2 = new \LimitIterator($it, 5, 10);
  38. 40 1 $it = new myIterator(); 2 $it2 = new

    \IteratorIterator($it); 3 $it3 = new \LimitIterator($it2, 5, 10);
  39. 42 1 $it = new ArrayIterator( 2 array("foo", "bar", array("qux",

    "wox"), "baz")); 3 4 foreach ($it as $v) { 5 print $v . "\n"; 6 }
  40. 42 1 $it = new ArrayIterator( 2 array("foo", "bar", array("qux",

    "wox"), "baz")); 3 4 foreach ($it as $v) { 5 print $v . "\n"; 6 } foo bar Array baz
  41. 43 1 $it = new RecursiveArrayIterator( 2 array("foo", "bar", array("qux",

    "wox"), "baz")); 3 4 foreach ($it as $v) { 5 print $v . "\n"; 6 }
  42. 43 1 $it = new RecursiveArrayIterator( 2 array("foo", "bar", array("qux",

    "wox"), "baz")); 3 4 foreach ($it as $v) { 5 print $v . "\n"; 6 } foo bar Array baz
  43. 44 1 $it = new RecursiveArrayIterator( 2 array("foo", "bar", array("qux",

    "wox"), "baz")); 3 $it2 = new RecursiveIteratorIterator($it); 4 5 foreach ($it2 as $v) { 6 print $v . "\n"; 7 }
  44. 44 1 $it = new RecursiveArrayIterator( 2 array("foo", "bar", array("qux",

    "wox"), "baz")); 3 $it2 = new RecursiveIteratorIterator($it); 4 5 foreach ($it2 as $v) { 6 print $v . "\n"; 7 } foo bar qux wox baz
  45. ➡ Enables recursivity ➡ Is a filter iterator (does not

    necessarily return all the elements) ➡ Filters through a callback function. 47
  46. ➡ It has “quirks” that are easily solvable (but breaks

    BC) ➡ Documentation is not always up to date. ➡ Naming is VERY confusing (caching iterator, recursiveIterator, seekableIterator) ➡ But the iterators are worth it! 49
  47. 51 ➡ SplDoublyLinkedList ➡ SplStack ➡ SplQueue ➡ SplHeap ➡

    SplMinHeap ➡ SplMaxHeap ➡ SplPriorityQueue ➡ SplFixedArray ➡ SplObjectStorage
  48. 52 ➡ Every data structure has its strength and weaknesses.

    ➡ Big-Oh O(1), O(n), O(log n) etc... ➡ Balance between time (CPU) and space (memory) ➡ PHP arrays are quite good! ➡ But sometimes other data structures are better.
  49. 55

  50. 58

  51. 61 ➡ Use wisely: ➡ Don’t use SplStack / SplQueue

    for random reads. ➡ Don’t use FixedArrays when you need speed boosts.
  52. ➡ BadFunctionCallException ➡ BadMethodCallException ➡ DomainException ➡ InvalidArgumentException ➡ LengthException

    ➡ LogicException ➡ OutOfBoundsException ➡ OutOfRangeException ➡ OverflowException ➡ RangeException ➡ RuntimeException ➡ UnderflowException ➡ UnexpectedValueException 63
  53. ➡ BadFunctionCallException ➡ BadMethodCallException ➡ DomainException ➡ InvalidArgumentException ➡ LengthException

    ➡ OutOfRangeException 64 Logic Exceptions Runtime Exceptions ➡ OutOfBoundsException ➡ OverflowException ➡ RangeException ➡ UnderflowException ➡ UnexpectedValueException
  54. 65 1 function foo($str) { 2 if ($str == "The

    Spanish Inquisition") { 3 throw new \UnexpectedValueException("Nobody expects ".$str); 4 } 5 /* ... */ 6 }
  55. 66 1 function foo($str) { 2 if ($str == "The

    Spanish Inquisition") { 3 throw new \InvalidArgumentException("Nobody expects ".$str); 4 } 5 /* ... */ 6 } Logic, not runtime
  56. 67 1 function foo($str) { 2 if ($str == "The

    Spanish Inquisition") { 3 /* logic */ 4 throw new \InvalidArgumentException("Nobody expects ".$str); 5 } 6 7 try { 8 $this->getDatabase()->saveRecord($str); 9 } catch (\RuntimeException $e) { 10 /* We could try again here */ 11 } catch (\Exception $e) { 12 /* Sorry, something else occurred. */ 13 } 14 }
  57. 76 1 $a = array("foo", "bar"); 2 $b = $a;

    3 $b[] = "baz"; 4 5 print_r ($a); 6 print_r ($b);
  58. 76 1 $a = array("foo", "bar"); 2 $b = $a;

    3 $b[] = "baz"; 4 5 print_r ($a); 6 print_r ($b); Array ( [0] => foo [1] => bar ) Array ( [0] => foo [1] => bar [2] => baz )
  59. 77 1 $a = new ArrayObject(); 2 $a[] = "foo";

    3 $a[] = "bar"; 4 5 $b = $a; 6 $b[] = "baz"; 7 8 print_r (iterator_to_array($a)); 9 print_r (iterator_to_array($b));
  60. 77 1 $a = new ArrayObject(); 2 $a[] = "foo";

    3 $a[] = "bar"; 4 5 $b = $a; 6 $b[] = "baz"; 7 8 print_r (iterator_to_array($a)); 9 print_r (iterator_to_array($b)); Array ( [0] => foo [1] => bar [2] => baz ) Array ( [0] => foo [1] => bar [2] => baz )
  61. 79 ➡ The (first and only) book about the SPL.

    ➡ Written by me (so you know it’s good :P) ➡ Fixes the documentation problem of the SPL (or a wobbly table)
  62. 80

  63. ➡ Adaption of the SPL will only happen when developers

    can become familiar with it. ➡ There is currently no real way to familiarize yourself with the SPL. 80
  64. 83 Find me on twitter: @jaytaph Find me for development

    and training: www.noxlogic.nl Find me on email: [email protected] Find me for blogs: www.adayinthelifeof.nl