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

(Re)discovering the SPL - IPC14

Joshua Thijssen
June 02, 2014
59

(Re)discovering the SPL - IPC14

Joshua Thijssen

June 02, 2014
Tweet

Transcript

  1. 5

  2. 5

  3. 6

  4. 7

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

    Miscellaneous functionality 8 Every SPL talk available:
  6. 12

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

    (instanceof). ➡ foreach() detects traversable interfaces and does magic. 12
  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 ) } 15 Iterator interface:
  9. $dir = opendir("."); while (($file = readdir($dir)) !== false) {

    # Business logic happens here print "file: $file\n"; } Let’s read directory content 17
  10. $dir = opendir("."); while (($file = readdir($dir)) !== false) {

    # hack: only display mp3 files if (! preg_match('|\.mp3$|i', $file)) { continue; } # Business logic happens here print "file: $file\n"; } 18 Filter on *.mp3
  11. ➡ Filter all MP3 and all JPG files. ➡ Filter

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

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

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

    (we can’t) ➡ How to reuse? (we can’t) 20
  17. $it = new DirectoryIterator("."); foreach ($it as $fi) { print

    "File: ".$fi->getPathname()."\n"; } 21 Directory Iterator
  18. $it = new DirectoryIterator("."); $it2 = new RegexIterator($it, "/\.mp3$/i"); foreach

    ($it2 as $fi) { print "File: ".$fi->getPathname()."\n"; } 22 Directory Iterator + filtering
  19. $it = new DirectoryIterator("."); $it2 = new RegexIterator($it, "/\.mp3$/i"); $it3

    = new FilesizeIterator($it2, 0, 6 * 1024 * 1024); $it4 = new LimitIterator($it3, 10, 5); foreach ($it4 as $fi) { print "File: ".$fi->getPathname()."\n"; } 23 Iterator chaining
  20. $it = new DirectoryIterator("."); $it2 = new RegexIterator($it, "/\.mp3$/i"); $it3

    = new FilesizeIterator($it2, 0, 6 * 1024 * 1024); $it4 = new LimitIterator($it3, 10, 5); foreach ($it4 as $fi) { print "File: ".$fi->getPathname()."\n"; } 23 Iterator chaining
  21. 24

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

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

    ✓ Testable Iterators can be tested separately. ✓ Maintainable No need to adapt our business logic. 24
  24. class myIterator implements \Iterator { ... } $a = array(1,

    2, 3); $it = new myIterator($a); print count($it); 26
  25. class myIterator implements \Iterator { ... } $a = array(1,

    2, 3); $it = new myIterator($a); print count($it); 1 26
  26. class myCountableIterator extends myIterator implements Countable { function count() {

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

    return count($this->_elements); } } $a = array(1, 2, 3, 4, 5); $it = new myCountableIterator($a); print count($it); 5 27
  28. class myCountableIterator extends myIterator implements Countable { function count() {

    return count($this->_arr); } } $a = array(1, 2, 3, 4, 5); $it = new myCountableIterator($a); $it2 = new limitIterator($it, 0, 3); print count($it2); 28
  29. class myCountableIterator extends myIterator implements Countable { function count() {

    return count($this->_arr); } } $a = array(1, 2, 3, 4, 5); $it = new myCountableIterator($a); $it2 = new limitIterator($it, 0, 3); print count($it2); 1 28
  30. 30

  31. ➡ It’s not an iterator, it’s an interface. ➡ seek()

    ➡ Implementing “seekableIterator” can speed up other iterators. 30
  32. ➡ It’s not an iterator, it’s an interface. ➡ seek()

    ➡ Implementing “seekableIterator” can speed up other iterators. ➡ LimitIterator makes use of “seekableIterator” 30
  33. 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
  34. 34

  35. 38 $it = new myIterator(); if ($it instanceof \IteratorAggregate) {

    $it = $it->getIterator(); } $it2 = new \LimitIterator($it, 5, 10);
  36. 41 $it = new ArrayIterator( array(“foo”, “bar”, array(“qux”, “wox”), “baz”));

    foreach ($it as $v) { print $v . “\n”; } foo bar Array baz
  37. 43 $it = new RecursiveArrayIterator( array(“foo”, “bar”, array(“qux”, “wox”), “baz”));

    $it2 = new RecursiveIteratorIterator($it); foreach ($it2 as $v) { print $v . “\n”; }
  38. 43 $it = new RecursiveArrayIterator( array(“foo”, “bar”, array(“qux”, “wox”), “baz”));

    $it2 = new RecursiveIteratorIterator($it); foreach ($it2 as $v) { print $v . “\n”; } foo bar qux wox baz
  39. ➡ Enables recursivity ➡ Is a filter iterator (does not

    necessarily return all the elements) ➡ Filters through a callback function. 46
  40. 49 ➡ Lookahead iterator ➡ Caches values, but not really

    :( ➡ Powerful __tostring() functionality (which probably no one uses)
  41. 50 $alphaIterator = new ArrayIterator(range("A", "Z")); $it = new CachingIterator($alphaIterator);

    foreach ($it as $v) { if (! $it->hasNext()) { print "last letter: "; } print $v . "\n"; } // A // ... // Y // last letter: Z
  42. 51 $alphaIterator = new ArrayIterator(range("A", "Z")); $it = new CachingIterator($alphaIterator);

    foreach ($it as $v) { if (! $it->hasNext()) { print "last letter: "; } print $v . "\n"; } print "The fourth letter of the alphabet is: ".$it[3]."\n";
  43. 52

  44. ➡ Don’t change cached data (you could, but don’t) ➡

    It doesn’t use the cached data on consecutive calls to the iterator. 52
  45. ➡ Don’t change cached data (you could, but don’t) ➡

    It doesn’t use the cached data on consecutive calls to the iterator. ➡ It clears the cache on a rewind() (and thus, a next foreach() loop) 52
  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! 54
  47. 56 ➡ SplDoublyLinkedList ➡ SplStack ➡ SplQueue ➡ SplHeap ➡

    SplMinHeap ➡ SplMaxHeap ➡ SplPriorityQueue ➡ SplFixedArray ➡ SplObjectStorage
  48. 57 ➡ 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. 60

  50. 63

  51. 66 ➡ 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 68
  53. ➡ BadFunctionCallException ➡ BadMethodCallException ➡ DomainException ➡ InvalidArgumentException ➡ LengthException

    ➡ OutOfRangeException 69 Logic Exceptions Runtime Exceptions ➡ OutOfBoundsException ➡ OverflowException ➡ RangeException ➡ UnderflowException ➡ UnexpectedValueException
  54. 70 function foo($str) { if ($str == “The Spanish Inquisition”)

    { throw new \UnexpectedValueException(“Nobody expects ”.$str); } ... }
  55. 71 function foo($str) { if ($str == “The Spanish Inquisition”)

    { throw new \InvalidArgumentException(“Nobody expects ”.$str); } ... } Logic, not runtime
  56. 72 function foo($str, $int) { if (! is_string($str)) { throw

    new \InvalidArgumentException(“Invalid type”); } if ($int < 0 || $int > 10) { throw new \OutOfRangeException(“should be between 0 and 10); } ... }
  57. 81 $a = array("foo", "bar"); $b = $a; $b[] =

    "baz"; print_r ($a); print_r ($b);
  58. 81 $a = array("foo", "bar"); $b = $a; $b[] =

    "baz"; print_r ($a); print_r ($b); Array ( [0] => foo [1] => bar ) Array ( [0] => foo [1] => bar [2] => baz )
  59. 82 $a = new ArrayObject(); $a[] = "foo"; $a[] =

    "bar"; $b = $a; $b[] = "baz"; print_r (iterator_to_array($a)); print_r (iterator_to_array($b));
  60. 82 $a = new ArrayObject(); $a[] = "foo"; $a[] =

    "bar"; $b = $a; $b[] = "baz"; print_r (iterator_to_array($a)); print_r (iterator_to_array($b)); Array ( [0] => foo [1] => bar [2] => baz ) Array ( [0] => foo [1] => bar [2] => baz )
  61. 84 ➡ 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. 85

  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. 85
  64. 88 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