Slide 1

Slide 1 text

1 Joshua Thijssen jaytaph (Re)discovering the SPL

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

3 Q: Have you ever used the SPL?

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

6

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

➡ 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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

11 INTERFACES

Slide 12

Slide 12 text

12 Traversable

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

14 Iterator

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

➡ 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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

$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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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:

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

25 iteratorAggregate

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

27 Countable

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

31 SeekableIterator

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

33 ITERATORS

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

36

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

38 IteratorIterator

Slide 39

Slide 39 text

39 Turns traversable “things” into an iterator

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

42 Recursive*Iterator

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

47 RecursiveCallbackFilterIterator

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

52 CachingIterator

Slide 53

Slide 53 text

53 2 for the price of 1

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

57 It doesn’t use the cached data!

Slide 58

Slide 58 text

58 DATA STRUCTURES

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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.

Slide 61

Slide 61 text

61 Quiz

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

63 SplQueue

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

66 SplPriorityQueue

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

70 SplObjectStorage

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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:

Slide 73

Slide 73 text

73 EXCEPTIONS

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

79 Never throw “Exception” Always catch “Exception”

Slide 80

Slide 80 text

80 MISC

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

82 Autoloader

Slide 83

Slide 83 text

83 spl_autoload_register(“spl_autoload_call”); Throws logicException

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

85 ArrayObject

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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 )

Slide 88

Slide 88 text

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 )

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

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)

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

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