(Re)discovering the SPL

1761ecd7fe763583553dde43e62c47bd?s=47 Joshua Thijssen
September 30, 2014
78

(Re)discovering the SPL

1761ecd7fe763583553dde43e62c47bd?s=128

Joshua Thijssen

September 30, 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
  3. 3 Tech nalyze WWW.TECHANALYZE.IO Your free credit code: drupalcon14

  4. 4 Q: Have you ever used the SPL?

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

    nuts?
  6. 6 SPL Documentation

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

  8. 7

  9. 8

  10. 9

  11. ➡ Not enough documentation. 9

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

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

    / missing in some cases. 9
  14. ➡ Interfaces ➡ Iterators ➡ Data structures ➡ Exceptions ➡

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

  16. 12 INTERFACES

  17. 13 Traversable (not an “spl interface”)

  18. 14

  19. ➡ Traversable cannot be implemented* 14

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

    (instanceof). 14
  21. ➡ Traversable cannot be implemented* ➡ Traversable can be detected

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

  23. Userland interface to make an object traversable 16

  24. 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:
  25. 18

  26. ➡ Iterator 18

  27. ➡ Iterator ➡ FilterIterators 18

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

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

    18
  30. ➡ Iterator ➡ FilterIterators ➡ “Chains” iterators together ➡ IteratorAggregate

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ✓ Testable Iterators can be tested separately. ✓ Maintainable No need to adapt our business logic. 26
  50. 27 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); 28
  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 28
  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); 29
  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 29
  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); 30
  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 30
  57. 31 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 32
  59. SPL Iterators 33 http://lxr.php.net/xref/PHP_5_5/ext/spl/internal/

  60. 34

  61. 35

  62. ➡ IteratorIterator? 35

  63. ➡ IteratorIterator? ➡ RecursiveIterator? 35

  64. ➡ IteratorIterator? ➡ RecursiveIterator? ➡ RecursiveIteratorIterator? 35

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

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

  67. 36 IteratorIterator

  68. 37 Turns traversable “things” into an iterator

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

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

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

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

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

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

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

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

    necessarily return all the elements) ➡ Filters through a callback function. 46
  81. 47 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! 48
  83. 49 DATA STRUCTURES

  84. 50 ➡ SplDoublyLinkedList ➡ SplStack ➡ SplQueue ➡ SplHeap ➡

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

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

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

  89. 54

  90. 54 SplQueue

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

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

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

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

  95. 57

  96. 57 SplPriorityQueue

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

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

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

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

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

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

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

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

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

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

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

  109. 68 MISC

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

    ➡ SplObserver / SplSubject 69
  111. 70 Autoloader

  112. 71 spl_autoload_register("spl_autoload_call");

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

  114. 72 spl_autoload_unregister("spl_autoload_call");

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

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

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

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

    3 $b[] = "baz"; 4 5 print_r ($a); 6 print_r ($b);
  119. 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 )
  120. 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));
  121. 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 )
  122. 77 How about the SPL & Drupal ?

  123. ➡ Not all that bad! ➡ Makes heavy use of

    iterators ➡ Exceptions are ok ➡ Too many new \Exceptions() (129) ➡ Datastructures not really 78
  124. 79 How can we make using the SPL easier?

  125. 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)
  126. 81

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

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

    maybe even solve them. 82
  130. http://farm1.static.flickr.com/73/163450213_18478d3aa6_d.jpg 83

  131. 84 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 Thanks!