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

(Re)discovering the SPL - PHPWorld

Joshua Thijssen
November 13, 2014
160

(Re)discovering the SPL - PHPWorld

Joshua Thijssen

November 13, 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 Tech nalyze WWW.TECHANALYZE.IO
  2. 6

  3. 7

  4. 8

  5. ➡ Interfaces ➡ Iterators ➡ Data structures ➡ Exceptions ➡

    Miscellaneous functionality 9 Every SPL talk available:
  6. 13

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

    (instanceof). ➡ foreach() detects traversable interfaces and does magic things. 13
  8. 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:
  9. 17

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

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

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

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

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

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

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

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

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

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

    ✓ Testable Iterators can be tested separately. ✓ Maintainable No need to adapt our business logic. 25
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. 33

  34. 34

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

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

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

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

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

    necessarily return all the elements) ➡ Filters through a callback function. 45
  44. ➡ 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
  45. 49 ➡ SplDoublyLinkedList ➡ SplStack ➡ SplQueue ➡ SplHeap ➡

    SplMinHeap ➡ SplMaxHeap ➡ SplPriorityQueue ➡ SplFixedArray ➡ SplObjectStorage
  46. 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.
  47. 53

  48. 56

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

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

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

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

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

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

    3 $b[] = "baz"; 4 5 print_r ($a); 6 print_r ($b);
  56. 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 )
  57. 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));
  58. 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 )
  59. 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)
  60. 78

  61. ➡ 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
  62. 81 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