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

(Re)discovering the SPL

Avatar for Joshua Thijssen Joshua Thijssen
October 13, 2014
380

(Re)discovering the SPL

Avatar for Joshua Thijssen

Joshua Thijssen

October 13, 2014
Tweet

More Decks by Joshua Thijssen

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. 7

  3. 8

  4. 9

  5. 14

  6. ➡ Traversable cannot be implemented* ➡ Traversable can be detected

    (instanceof). ➡ foreach() detects traversable interfaces and does magic things. 14
  7. 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 ) } 17 Iterator interface:
  8. 18

  9. 1 $dir = opendir("."); 2 while (($file = readdir($dir)) !==

    false) { 3 4 # Business logic happens here 5 print "file: $file\n"; 6 7 } 19
  10. 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 } 20
  11. ➡ Filter all MP3 and all JPG files. ➡ Filter

    all MP3 files that are larger than 6MB. 21
  12. ➡ Filter all MP3 and all JPG files. ➡ Filter

    all MP3 files that are larger than 6MB. ➡ Do not filter at all. 21
  13. ➡ 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. 21
  14. ➡ 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. 21
  15. 22

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

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

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

    "/\.mp3$/i"); 3 foreach ($it2 as $fi) { 4 print "File: ".$fi->getPathname()."\n"; 5 } 24
  19. 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 } 25
  20. 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 } 25
  21. 26

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

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

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

    3 } 4 5 $a = array(1, 2, 3); 6 $it = new myIterator($a); 7 8 print count($it); 28
  25. 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 28
  26. 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); 29
  27. 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 29
  28. 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); 30
  29. 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 30
  30. 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 32
  31. 34

  32. 35

  33. 38 1 $it = new myIterator(); 2 if ($it instanceof

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

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

    "wox"), "baz")); 3 4 foreach ($it as $v) { 5 print $v . "\n"; 6 }
  36. 41 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
  37. 42 1 $it = new RecursiveArrayIterator( 2 array("foo", "bar", array("qux",

    "wox"), "baz")); 3 4 foreach ($it as $v) { 5 print $v . "\n"; 6 }
  38. 42 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
  39. 43 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 }
  40. 43 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
  41. ➡ Enables recursivity ➡ Is a filter iterator (does not

    necessarily return all the elements) ➡ Filters through a callback function. 46
  42. ➡ 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! 48
  43. 50 ➡ SplDoublyLinkedList ➡ SplStack ➡ SplQueue ➡ SplHeap ➡

    SplMinHeap ➡ SplMaxHeap ➡ SplPriorityQueue ➡ SplFixedArray ➡ SplObjectStorage
  44. 51 ➡ 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.
  45. 54

  46. 57

  47. 60 ➡ Use wisely: ➡ Don’t use SplStack / SplQueue

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

    ➡ LogicException ➡ OutOfBoundsException ➡ OutOfRangeException ➡ OverflowException ➡ RangeException ➡ RuntimeException ➡ UnderflowException ➡ UnexpectedValueException 62
  49. ➡ BadFunctionCallException ➡ BadMethodCallException ➡ DomainException ➡ InvalidArgumentException ➡ LengthException

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

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

    Spanish Inquisition") { 3 throw new \InvalidArgumentException("Nobody expects ".$str); 4 } 5 /* ... */ 6 } Logic, not runtime
  52. 66 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 }
  53. 75 1 $a = array("foo", "bar"); 2 $b = $a;

    3 $b[] = "baz"; 4 5 print_r ($a); 6 print_r ($b);
  54. 75 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 )
  55. 76 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));
  56. 76 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 )
  57. ➡ Not all that bad! ➡ Makes heavy use of

    iterators ➡ Exceptions are ok ➡ Too many new \Exceptions() (129) ➡ Datastructures not really 78
  58. 80 ➡ 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)
  59. 81

  60. ➡ 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. 81
  61. 84 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 Symfony2 Webinar