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

(Re)discovering the SPL

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for Joshua Thijssen Joshua Thijssen
January 25, 2014
580

(Re)discovering the SPL

Avatar for Joshua Thijssen

Joshua Thijssen

January 25, 2014
Tweet

Transcript

  1. 2 Joshua Thijssen Freelance consultant, developer and trainer @ NoxLogic

    Founder of the Dutch Web Alliance Development in PHP, Python, C, Java. Lead developer of Saffire. Blog: http://adayinthelifeof.nl Email: [email protected] Twitter: @jaytaph
  2. 6

  3. ➡ 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. 8
  4. ➡ Traversable cannot be implemented. ➡ Traversable can be detected

    (instanceof). ➡ foreach() will use traversable interfaces. 13
  5. $dir = opendir("."); while (($file = readdir($dir)) !== false) {

    print "file: $file\n"; } Let’s read directory content 15
  6. $dir = opendir("."); while (($file = readdir($dir)) !== false) {

    if (! preg_match('|\.mp3$|i', $file)) { continue; } print "file: $file\n"; } 16 Filter on *.mp3
  7. ➡ 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. 17
  8. ➡ How to test? ➡ How to maintain? ➡ How

    to reuse? 18 $dir = opendir("."); while (($file = readdir($dir)) !== false) { if (! preg_match('|\.mp3$|i', $file)) { continue; } print "file: $file\n"; }
  9. $it = new DirectoryIterator("."); foreach ($it as $fi) { print

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

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

    = new FilesizeIterator($it, 6 * 1024 * 1024); $it = new LimitIterator($it, 10, 5); foreach ($it as $fi) { print "File: ".$fi->getPathname()."\n"; } 21 Iterator chaining
  12. ✓ Reusable We can use iterators where ever we want.

    ✓ Testable Iterators can be tested separately. ✓ Maintainable No need to adapt our business logic. 22
  13. 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 ) } 23 Iterator interface:
  14. reset($a); while (current($a) !== false) { $key = key($a); $current

    = current($a); print “K: $key C: $current\n”; next($a); } Rewind() valid() 24
  15. ➡ Object that HAS an iterator ➡ but not IS

    an iterator ➡ Separation of business object and iteration logic ➡ Even runtime / dynamic iterators (through DI) 26
  16. class myIterator extends Iterator { ... } $a = array(1,

    2, 3); $it = new myIterator($a); print count($it); 1 28
  17. 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 29
  18. class myCountableIterator extends myIterator implements Countable { function count() {

    return count($this->_arr); } } $a = array(1, 2, 3, 4, 5); $it = new myCountableIterator($a); $it = new limitIterator($it, 0, 3); print count($it); 1 30
  19. ➡ It’s not an iterator, it’s an interface. ➡ seek()

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

  22. 40 $it = new myIterator(); if ($it instanceof IteratorAggregate) {

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

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

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

    necessarily return all the elements) ➡ Filters through a callback function. 48
  26. 49 $it = new RecursiveDirectoryIterator(“/”); $it = new RecursiveCallbackFilterIterator($it, function

    ($value, $key, $it) { return ($value->getSize() < 1024); }); $it = new RecursiveIteratorIterator($it) foreach ($it as $item) { print $item->getSize() . “ “ . $item->getPathName().”\n”; }
  27. 50 $it = new RecursiveDirectoryIterator(“/”); $it = new RecursiveCallbackFilterIterator($it, function

    ($value, $key, $it) { return ($value->isDir() || $value->getSize() < 1024); }); $it = new RecursiveIteratorIterator($it); foreach ($it as $item) { print $item->getSize() . “ “ . $item->getPathName().”\n”; }
  28. 51 $it = new RecursiveDirectoryIterator(“/”); $it = new RecursiveCallbackFilterIterator($it, function

    ($value, $key, $it) { return ($value->isDir() || $value->getSize() < 1024); }); $it = new RecursiveIteratorIterator($it); $it = new CallbackFilterIterator($it, function ($value, $key, $it) { return ! $value->isDir(); }); foreach ($it as $item) { print $item->getSize() . “ “ . $item->getPathName().”\n”; }
  29. 54 ➡ Lookahead iterator ➡ Caches values, but not really

    ➡ Powerful __tostring() functionality
  30. 55 $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
  31. 56 $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";
  32. 59 ➡ SplDoublyLinkedList ➡ SplStack ➡ SplQueue ➡ SplHeap ➡

    SplMinHeap ➡ SplMaxHeap ➡ SplPriorityQueue ➡ SplFixedArray ➡ SplObjectStorage
  33. 60 ➡ 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 aren’t bad! ➡ But sometimes other data structures are better.
  34. 69 ➡ Use wisely: ➡ Don’t use SplStack / SplQueue

    for random reads. ➡ Don’t use FixedArrays when you need speed boosts
  35. 71 $map = new SplObjectStorage(); $map[$obj1] = $info1; $map[$obj2] =

    $info2; print_r ($map[$obj2]); $set = new SplObjectStorage(); $set->attach($obj1); print_r ($set->contains($obj1)); splObjectStorage as a set splObjectStorage as a map
  36. 72 class MyStorage extends SplObjectStorage { function getHash($object) { return

    $object->type; } } $obj1 = new StdClass(); $obj1->type = “foo”; $obj2 = new StdClass(); $obj2->type = “bar”; $obj3 = new StdClass(); $obj3->type = “foo”; $store = new MyStorage(); $store->attach($obj1); // Added $store->attach($obj2); // Added $store->attach($obj3); // Not added:same type (thus hash) already present! Defining what to store:
  37. ➡ BadFunctionCallException ➡ BadMethodCallException ➡ DomainException ➡ InvalidArgumentException ➡ LengthException

    ➡ LogicException ➡ OutOfBoundsException ➡ OutOfRangeException ➡ OverflowException ➡ RangeException ➡ RuntimeException ➡ UnderflowException ➡ UnexpectedValueException 74
  38. ➡ BadFunctionCallException ➡ BadMethodCallException ➡ DomainException ➡ InvalidArgumentException ➡ LengthException

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

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

    { throw new \InvalidArgumentException(“Nobody expects ”.$str); } ... } Logic, not runtime
  41. 78 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); } ... }
  42. 87 $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 )
  43. 88 $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 )
  44. 90 ➡ 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)
  45. 93 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 https://joind.in/10260