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

(Re)discovering the SPL

Joshua Thijssen
January 25, 2014
370

(Re)discovering the SPL

Joshua Thijssen

January 25, 2014
Tweet

Transcript

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

    View full-size slide

  2. 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

    View full-size slide

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

    View full-size slide

  4. 4
    Q: Have you ever used the SPL
    and didn’t went nuts?

    View full-size slide

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

    View full-size slide

  6. ➡ Not enough documentation.
    ➡ Very few examples.
    ➡ Wrong / missing in some cases.
    7

    View full-size slide

  7. ➡ 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

    View full-size slide

  8. ➡ Interfaces
    ➡ Iterators
    ➡ Data structures
    ➡ Exceptions
    ➡ Miscellaneous functionality
    9

    View full-size slide

  9. 10
    Don’t get scared!
    The SPL is awesomesauce!

    View full-size slide

  10. 11
    INTERFACES

    View full-size slide

  11. 12
    Traversable

    View full-size slide

  12. ➡ Traversable cannot be implemented.
    ➡ Traversable can be detected (instanceof).
    ➡ foreach() will use traversable interfaces.
    13

    View full-size slide

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

    View full-size slide

  14. $dir = opendir(".");
    while (($file = readdir($dir)) !== false) {
    if (! preg_match('|\.mp3$|i', $file)) {
    continue;
    }
    print "file: $file\n";
    }
    16
    Filter on *.mp3

    View full-size slide

  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.
    ➡ Search multiple directories.
    17

    View full-size slide

  16. ➡ 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";
    }

    View full-size slide

  17. $it = new DirectoryIterator(".");
    foreach ($it as $fi) {
    print "File: ".$fi->getPathname()."\n";
    }
    19
    Directory Iterator

    View full-size slide

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

    View full-size slide

  19. $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

    View full-size slide

  20. ✓ Reusable
    We can use iterators where ever we want.
    ✓ Testable
    Iterators can be tested separately.
    ✓ Maintainable
    No need to adapt our business logic.
    22

    View full-size slide

  21. 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:

    View full-size slide

  22. reset($a);
    while (current($a) !== false) {
    $key = key($a);
    $current = current($a);
    print “K: $key C: $current\n”;
    next($a);
    }
    Rewind()
    valid()
    24

    View full-size slide

  23. 25
    iteratorAggregate

    View full-size slide

  24. ➡ Object that HAS an iterator
    ➡ but not IS an iterator
    ➡ Separation of business object and
    iteration logic
    ➡ Even runtime / dynamic iterators
    (through DI)
    26

    View full-size slide

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

    View full-size slide

  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);
    5
    29

    View full-size slide

  27. 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

    View full-size slide

  28. 31
    SeekableIterator

    View full-size slide

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

    View full-size slide

  30. 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

    View full-size slide

  31. SPL Iterators
    35
    http://lxr.php.net/xref/PHP_5_5/ext/spl/internal/

    View full-size slide

  32. ➡ IteratorIterator?
    ➡ RecursiveIterator?
    ➡ RecursiveIteratorIterator?
    ➡ RecursiveCallbackFilterIterator?
    ➡ Really!?!?
    37

    View full-size slide

  33. 38
    IteratorIterator

    View full-size slide

  34. 39
    Turns traversable “things” into an iterator

    View full-size slide

  35. 40
    $it = new myIterator();
    if ($it instanceof IteratorAggregate) {
    $it = $it->getIterator();
    }
    $it = new LimitIterator($it, 5, 10);

    View full-size slide

  36. 41
    $it = new myIterator();
    $it = new IteratorIterator($it);
    $it = new LimitIterator($it, 5, 10);

    View full-size slide

  37. 42
    Recursive*Iterator

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  40. 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

    View full-size slide

  41. 46
    “Recursive” iterators add the POSSIBILITY
    to recursively iterate over data.
    You still need to implement it!

    View full-size slide

  42. 47
    RecursiveCallbackFilterIterator

    View full-size slide

  43. ➡ Enables recursivity
    ➡ Is a filter iterator (does not necessarily
    return all the elements)
    ➡ Filters through a callback function.
    48

    View full-size slide

  44. 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”;
    }

    View full-size slide

  45. 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”;
    }

    View full-size slide

  46. 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”;
    }

    View full-size slide

  47. 52
    CachingIterator

    View full-size slide

  48. 53
    2 for the price of 1

    View full-size slide

  49. 54
    ➡ Lookahead iterator
    ➡ Caches values, but not really
    ➡ Powerful __tostring() functionality

    View full-size slide

  50. 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

    View full-size slide

  51. 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";

    View full-size slide

  52. 57
    It doesn’t use the cached data!

    View full-size slide

  53. 58
    DATA STRUCTURES

    View full-size slide

  54. 59
    ➡ SplDoublyLinkedList
    ➡ SplStack
    ➡ SplQueue
    ➡ SplHeap
    ➡ SplMinHeap
    ➡ SplMaxHeap
    ➡ SplPriorityQueue
    ➡ SplFixedArray
    ➡ SplObjectStorage

    View full-size slide

  55. 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.

    View full-size slide

  56. 62
    http://www.flickr.com/photos/sostark/26697448/
    SplStack

    View full-size slide

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

    View full-size slide

  58. 65
    http://www.flickr.com/photos/pediddle/54326823/
    SplObjectStorage

    View full-size slide

  59. 66
    SplPriorityQueue

    View full-size slide

  60. 67
    http://farm4.static.flickr.com/3224/3072017987_ee454536da.jpg
    SplHeap

    View full-size slide

  61. 68
    http://en.wikipedia.org/wiki/File:USA.NM.VeryLargeArray.02.jpg
    SplFixedArray

    View full-size slide

  62. 69
    ➡ Use wisely:
    ➡ Don’t use SplStack / SplQueue for
    random reads.
    ➡ Don’t use FixedArrays when you need
    speed boosts

    View full-size slide

  63. 70
    SplObjectStorage

    View full-size slide

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

    View full-size slide

  65. 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:

    View full-size slide

  66. 73
    EXCEPTIONS

    View full-size slide

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

    View full-size slide

  68. ➡ BadFunctionCallException
    ➡ BadMethodCallException
    ➡ DomainException
    ➡ InvalidArgumentException
    ➡ LengthException
    ➡ OutOfRangeException
    75
    Logic Exceptions Runtime Exceptions
    ➡ OutOfBoundsException
    ➡ OverflowException
    ➡ RangeException
    ➡ UnderflowException
    ➡ UnexpectedValueException

    View full-size slide

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

    View full-size slide

  70. 77
    function foo($str) {
    if ($str == “The Spanish Inquisition”) {
    throw new \InvalidArgumentException(“Nobody expects ”.$str);
    }
    ...
    }
    Logic, not runtime

    View full-size slide

  71. 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);
    }
    ...
    }

    View full-size slide

  72. 79
    Never throw “Exception”
    Always catch “Exception”

    View full-size slide

  73. ➡ SPL Autoloading
    ➡ SplFileInfo class
    ➡ Spl(Temp)FileObject
    ➡ ArrayObject
    ➡ SplObserver / SplSubject
    81

    View full-size slide

  74. 82
    Autoloader

    View full-size slide

  75. 83
    spl_autoload_register(“spl_autoload_call”);
    Throws logicException

    View full-size slide

  76. 84
    spl_autoload_unregister(“spl_autoload_call”);
    Removes ALL the autoloaders!

    View full-size slide

  77. 85
    ArrayObject

    View full-size slide

  78. 86
    ArrayObjects are not objects that acts like arrays
    ArrayObjects are objects that acts like arrays

    View full-size slide

  79. 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
    )

    View full-size slide

  80. 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
    )

    View full-size slide

  81. 89
    How can we make using the SPL easier?
    http://noscope.com/photostream/albums/various/I_Want_To_Believe_01.jpg

    View full-size slide

  82. 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)

    View full-size slide

  83. ➡ BLOG!
    ➡ Update documentation.
    ➡ Find the quirks (and maybe even solve
    them).
    91

    View full-size slide

  84. http://farm1.static.flickr.com/73/163450213_18478d3aa6_d.jpg 92

    View full-size slide

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

    View full-size slide