$30 off During Our Annual Pro Sale. View Details »

(Re)discovering the SPL - PFC13

Joshua Thijssen
September 14, 2013
75

(Re)discovering the SPL - PFC13

Joshua Thijssen

September 14, 2013
Tweet

Transcript

  1. (re)discovering
    Web&PHP - San Jose - USA
    16-18 september 2013
    the Standard PHP Library
    1

    View Slide

  2. 2
    Joshua Thijssen
    Freelance consultant, developer and
    trainer @ NoxLogic
    Founder of the Dutch Web Alliance
    Development in PHP, Python, Perl, C,
    Java. Lead developer of Saffire.
    Blog: http://adayinthelifeof.nl
    Email: [email protected]
    Twitter: @jaytaph

    View Slide

  3. 3
    Have you ever used the SPL?

    View Slide

  4. 4
    Have you ever used the SPL,
    and not want to apply for a job as C# developer?

    View Slide

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

    View Slide

  6. 6

    View Slide

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

    View Slide

  8. ➡ Adaption of the SPL will only occur when
    developers can become familiar with it.
    ➡ There is currently no real way to familiarize
    yourself with the SPL.
    ➡ :(
    8

    View Slide

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

    View Slide

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

    View Slide

  11. 11
    INTERFACES

    View Slide

  12. 12

    View Slide

  13. 13
    Traversable

    View Slide

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

    View Slide

  15. 15
    Iterator

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  19. ➡ How to test?
    ➡ How to maintain?
    ➡ How to reuse?
    19
    $dir = opendir(".");
    while (($file = readdir($dir)) !== false) {
    if (! preg_match('|\.mp3$|i', $file)) {
    continue;
    }
    print "file: $file\n";
    }

    View Slide

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

    View Slide

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

    View Slide

  22. $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";
    }
    22
    Iterator chaining

    View Slide

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

    View Slide

  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 )
    }
    24

    View Slide

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

    View Slide

  26. 26
    Countable

    View Slide

  27. $a = array(1, 2, 3);
    $it = new myIterator($a);
    print count($it);
    1
    27

    View Slide

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

    View Slide

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

    View Slide

  30. 30
    SeekableIterator

    View Slide

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

    View Slide

  32. 32
    ITERATORS

    View Slide

  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
    33

    View Slide

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

    View Slide

  35. ➡ IteratorIterator?
    ➡ RecursiveIterator?
    ➡ RecursiveIteratorIterator?
    ➡ RecursiveCallbackFilterIterator?
    ➡ Really!?!?
    35

    View Slide

  36. 36
    IteratorIterator

    View Slide

  37. 37
    Turns traversable “things” into an iterator

    View Slide

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

    View Slide

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

    View Slide

  40. 40
    Recursive*Iterator

    View Slide

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

    View Slide

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

    View Slide

  43. 43
    $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 Slide

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

    View Slide

  45. 45
    RecursiveCallbackFilterIterator

    View Slide

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

    View Slide

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

    View Slide

  48. 48
    CachingIterator

    View Slide

  49. 49
    2 for the price of 1

    View Slide

  50. 50
    ➡ Lookahead iterator
    ➡ Caches values
    ➡ Powerful __tostring() functionality

    View Slide

  51. 51
    $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 Slide

  52. 52
    $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 Slide

  53. 53
    It doesn’t use the cached data!

    View Slide

  54. 54
    DATA STRUCTURES

    View Slide

  55. 55
    ➡ SplDoublyLinkedList
    ➡ SplStack
    ➡ SplQueue
    ➡ SplHeap
    ➡ SplMinHeap
    ➡ SplMaxHeap
    ➡ SplPriorityQueue
    ➡ SplFixedArray
    ➡ SplObjectStorage

    View Slide

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

  57. 57
    Quiz

    View Slide

  58. 58
    http://www.flickr.com/photos/sostark/26697448/
    SplStack

    View Slide

  59. 59
    SplQueue

    View Slide

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

    View Slide

  61. 61
    http://www.flickr.com/photos/pediddle/54326823/
    SplObjectStorage

    View Slide

  62. 62
    SplPriorityQueue

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  66. 66
    SplObjectStorage

    View Slide

  67. 67
    $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 Slide

  68. 68
    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 Slide

  69. 69
    EXCEPTIONS

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  74. 74
    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 Slide

  75. 75
    class InvalidDateException extends DomainException { }
    class ChristmasException extends DomainException { }
    class Calendar {
    function addAppointment(DateTime $date, $appointment) {
    if ($date->format("dm") == "2512") {
    throw new \ChristmasException(
    "Cannot add appointment on christmas day");
    }
    $weekday = $date->format("N");
    if ($weekday >= 6) {
    throw new \InvalidDateException(
    "Cannot add appointment in the weekend");
    }
    ....
    }
    }

    View Slide

  76. 76
    Never throw “Exception”
    Always catch “Exception”

    View Slide

  77. 77
    Exceptions should not be
    part of your flow...
    They’re: exceptions

    View Slide

  78. 78
    MISC

    View Slide

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

    View Slide

  80. 80
    Autoloader

    View Slide

  81. 81
    spl_autoload_register(“spl_autoload_call”);
    Throws logicException

    View Slide

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

    View Slide

  83. 83
    ArrayObject

    View Slide

  84. 84
    ArrayObjects are not objects that acts like arrays
    ArrayObjects are objects that acts like arrays

    View Slide

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

  86. 86
    $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 Slide

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

    View Slide

  88. 88
    ➡ The (first and only)
    book about the SPL.
    ➡ Written by me (so
    you know it’s good :P)
    ➡ Tries and fix the
    documentation
    problem of the SPL.

    View Slide

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

    View Slide

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

    View Slide