(Re)discovering the SPL - PHPWorld

1761ecd7fe763583553dde43e62c47bd?s=47 Joshua Thijssen
November 13, 2014
120

(Re)discovering the SPL - PHPWorld

1761ecd7fe763583553dde43e62c47bd?s=128

Joshua Thijssen

November 13, 2014
Tweet

Transcript

  1. 1 Joshua Thijssen jaytaph (Re)discovering the SPL

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

    of TechAnalyze.io Founder of the Dutch Web Alliance Blog: http://adayinthelifeof.nl Email: jthijssen@noxlogic.nl Twitter: @jaytaph Tech nalyze WWW.TECHANALYZE.IO
  3. 3 Q: Have you ever used the SPL?

  4. 4 Q: Have you ever used the SPL without going

    nuts?
  5. 5 SPL Documentation

  6. 5 SPL Documentation http://www.php.net/spl

  7. 6

  8. 7

  9. 8

  10. ➡ Not enough documentation. 8

  11. ➡ Not enough documentation. ➡ Very few examples. 8

  12. ➡ Not enough documentation. ➡ Very few examples. ➡ Wrong

    / missing in some cases. 8
  13. ➡ Interfaces ➡ Iterators ➡ Data structures ➡ Exceptions ➡

    Miscellaneous functionality 9 Every SPL talk available:
  14. 10 Don’t get scared! The SPL is awesomesauce!

  15. 11 INTERFACES

  16. 12 Traversable (not an “spl interface”)

  17. 13

  18. ➡ Traversable cannot be implemented* 13

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

    (instanceof). 13
  20. ➡ Traversable cannot be implemented* ➡ Traversable can be detected

    (instanceof). ➡ foreach() detects traversable interfaces and does magic things. 13
  21. 14 Iterator (still not an “spl interface”)

  22. Userland interface to make an object traversable 15

  23. 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:
  24. 17

  25. ➡ Iterator 17

  26. ➡ Iterator ➡ FilterIterators 17

  27. ➡ Iterator ➡ FilterIterators ➡ “Chains” iterators together 17

  28. ➡ Iterator ➡ FilterIterators ➡ “Chains” iterators together ➡ IteratorAggregate

    17
  29. ➡ Iterator ➡ FilterIterators ➡ “Chains” iterators together ➡ IteratorAggregate

    ➡ Is not an iterator, but HAS an iterator 17
  30. 1 $dir = opendir("."); 2 while (($file = readdir($dir)) !==

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

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

  34. ➡ Filter all MP3 and all JPG files. ➡ Filter

    all MP3 files that are larger than 6MB. 20
  35. ➡ Filter all MP3 and all JPG files. ➡ Filter

    all MP3 files that are larger than 6MB. ➡ Do not filter at all. 20
  36. ➡ 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. 20
  37. ➡ 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. 20
  38. 21

  39. ➡ How to test? (we can’t) 21

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

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

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

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

    "/\.mp3$/i"); 3 foreach ($it2 as $fi) { 4 print "File: ".$fi->getPathname()."\n"; 5 } 23
  44. 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, 5, 3); 5 6 foreach ($it4 as $fi) { 7 print "File: ".$fi->getPathname()."\n"; 8 } 24
  45. 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, 5, 3); 5 6 foreach ($it4 as $fi) { 7 print "File: ".$fi->getPathname()."\n"; 8 } 24
  46. 25

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

    25
  48. ✓ Reusable We can use iterators where ever we want.

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

    ✓ Testable Iterators can be tested separately. ✓ Maintainable No need to adapt our business logic. 25
  50. 26 Countable (hurrah! An “spl interface”!)

  51. 1 class myIterator implements \Iterator { 2 /* ... */

    3 } 4 5 $a = array(1, 2, 3); 6 $it = new myIterator($a); 7 8 print count($it); 27
  52. 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 27
  53. 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); 28
  54. 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 28
  55. 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); 29
  56. 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 29
  57. 30 ITERATORS

  58. 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 31
  59. SPL Iterators 32 http://lxr.php.net/xref/PHP_5_5/ext/spl/internal/

  60. 33

  61. 34

  62. ➡ IteratorIterator? 34

  63. ➡ IteratorIterator? ➡ RecursiveIterator? 34

  64. ➡ IteratorIterator? ➡ RecursiveIterator? ➡ RecursiveIteratorIterator? 34

  65. ➡ IteratorIterator? ➡ RecursiveIterator? ➡ RecursiveIteratorIterator? ➡ RecursiveCallbackFilterIterator? 34

  66. ➡ IteratorIterator? ➡ RecursiveIterator? ➡ RecursiveIteratorIterator? ➡ RecursiveCallbackFilterIterator? 34

  67. 35 IteratorIterator

  68. 36 Turns traversable “things” into an iterator

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

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

    \IteratorIterator($it); 3 $it3 = new \LimitIterator($it2, 5, 10);
  71. 39 Recursive*Iterator

  72. 40 1 $it = new ArrayIterator( 2 array("foo", "bar", array("qux",

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

    "wox"), "baz")); 3 4 foreach ($it as $v) { 5 print $v . "\n"; 6 }
  75. 41 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
  76. 42 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 }
  77. 42 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
  78. 43 “Recursive” iterators add the POSSIBILITY to recursively iterate over

    data. You still need to implement it!
  79. 44 RecursiveCallbackFilterIterator

  80. ➡ Enables recursivity ➡ Is a filter iterator (does not

    necessarily return all the elements) ➡ Filters through a callback function. 45
  81. 46 SPL Iterators,..

  82. ➡ 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! 47
  83. 48 DATA STRUCTURES

  84. 49 ➡ SplDoublyLinkedList ➡ SplStack ➡ SplQueue ➡ SplHeap ➡

    SplMinHeap ➡ SplMaxHeap ➡ SplPriorityQueue ➡ SplFixedArray ➡ SplObjectStorage
  85. 50 ➡ 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.
  86. 51 PubQuiz

  87. 52 http://www.flickr.com/photos/sostark/26697448/

  88. 52 http://www.flickr.com/photos/sostark/26697448/ SplStack

  89. 53

  90. 53 SplQueue

  91. 54 http://www.flickr.com/photos/blogchef/4764248456/sizes/z/in/photostream/

  92. 54 http://www.flickr.com/photos/blogchef/4764248456/sizes/z/in/photostream/ Spl(Doubly)LinkedList

  93. 55 http://www.flickr.com/photos/pediddle/54326823/

  94. 55 http://www.flickr.com/photos/pediddle/54326823/ SplObjectStorage

  95. 56

  96. 56 SplPriorityQueue

  97. 57 http://farm4.static.flickr.com/3224/3072017987_ee454536da.jpg

  98. 57 http://farm4.static.flickr.com/3224/3072017987_ee454536da.jpg SplHeap

  99. 58 http://en.wikipedia.org/wiki/File:USA.NM.VeryLargeArray.02.jpg

  100. 58 http://en.wikipedia.org/wiki/File:USA.NM.VeryLargeArray.02.jpg SplFixedArray

  101. 59 ➡ Use wisely: ➡ Don’t use SplStack / SplQueue

    for random reads. ➡ Don’t use FixedArrays when you need speed boosts.
  102. 60 EXCEPTIONS

  103. ➡ BadFunctionCallException ➡ BadMethodCallException ➡ DomainException ➡ InvalidArgumentException ➡ LengthException

    ➡ LogicException ➡ OutOfBoundsException ➡ OutOfRangeException ➡ OverflowException ➡ RangeException ➡ RuntimeException ➡ UnderflowException ➡ UnexpectedValueException 61
  104. ➡ BadFunctionCallException ➡ BadMethodCallException ➡ DomainException ➡ InvalidArgumentException ➡ LengthException

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

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

    Spanish Inquisition") { 3 throw new \InvalidArgumentException("Nobody expects ".$str); 4 } 5 /* ... */ 6 } Logic, not runtime
  107. 65 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 }
  108. 66 Never throw “\Exception” Always catch “\Exception”

  109. 67 MISC

  110. ➡ SPL Autoloading ➡ SplFileInfo class ➡ Spl(Temp)FileObject ➡ ArrayObject

    ➡ SplObserver / SplSubject 68
  111. 69 Autoloader

  112. 70 spl_autoload_register("spl_autoload_call");

  113. 70 spl_autoload_register("spl_autoload_call"); Throws logicException

  114. 71 spl_autoload_unregister("spl_autoload_call");

  115. 71 spl_autoload_unregister("spl_autoload_call"); - Removes ALL the autoloaders! - Destroys the

    autoload stack. - Set your house on fire.
  116. 72 ArrayObject

  117. 73 ArrayObjects are not objects that acts like arrays ArrayObjects

    are objects that acts like arrays
  118. 74 1 $a = array("foo", "bar"); 2 $b = $a;

    3 $b[] = "baz"; 4 5 print_r ($a); 6 print_r ($b);
  119. 74 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 )
  120. 75 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));
  121. 75 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 )
  122. 76 How can we make using the SPL easier?

  123. 77 ➡ 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)
  124. 78

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

    can become familiar with it. 78
  126. ➡ 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. 78
  127. ➡ BLOG! ➡ Update documentation. ➡ Find the quirks, and

    maybe even solve them. 79
  128. http://farm1.static.flickr.com/73/163450213_18478d3aa6_d.jpg 80

  129. 81 Find me on twitter: @jaytaph Find me for development

    and training: www.noxlogic.nl Find me on email: jthijssen@noxlogic.nl Find me for blogs: www.adayinthelifeof.nl