Slide 1

Slide 1 text

Dark Corners of the SPL Photo By: SSG Ryan Boas Midwest PHP 2019

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Photo By: Tom Walsh

Slide 5

Slide 5 text

Photo By: NASA Goddard Space Flight Center

Slide 6

Slide 6 text

Data Structures SplDoublyLinkedList SplStack SplQueue SplHeap SplMaxHeap SplMinHeap SplPriorityQueue SplFixedArray SplObjectStorage https://secure.php.net/manual/en/spl.datastructures.php

Slide 7

Slide 7 text

Big-O O(1) - Constant no matter how big your data O(log n) - Grows slowly with your data O(n) - Grows linearly with your data O(n2) - Grows quadratically with your data O(2n) - Grows exponentially with your data O(n!) - LOL https://en.wikipedia.org/wiki/Big_O

Slide 8

Slide 8 text

Photo By: Cmglee

Slide 9

Slide 9 text

Performance SPL version versus simple array 1,000,000 random elements Sorting, iterating, or both Time and memory usage

Slide 10

Slide 10 text

Data Structures SplDoublyLinkedList SplStack SplQueue SplPriorityQueue SplFixedArray SplObjectStorage SplHeap SplMaxHeap SplMinHeap

Slide 11

Slide 11 text

Image By: Bhavikp19

Slide 12

Slide 12 text

SplDoublyLinkedList Access: O(n) Search: O(n) Insert: O(1) Delete: O(1)

Slide 13

Slide 13 text

$list = new SplDoublyLinkedList(); $list->push('Ash'); $list->push('Bingo'); $list->push('Charlie'); $list->push('Echo'); foreach ($list as $key => $character) { echo $key, ' ', $character, PHP_EOL; } echo PHP_EOL; https://github.com/omnicolor/dark-corners-of-the-spl/blob/master/SplDoublyLinkedList.php

Slide 14

Slide 14 text

$list->push('Echo'); foreach ($list as $key => $character) { echo $key, ' ', $character, PHP_EOL; } echo PHP_EOL; 0 Ash 1 Bingo 2 Charlie 3 Echo

Slide 15

Slide 15 text

0 Ash 1 Bingo 2 Charlie 3 Echo $list->add(3, 'Delta'); foreach ($list as $key => $character) { echo $key, ' ', $character, PHP_EOL; } echo PHP_EOL;

Slide 16

Slide 16 text

foreach ($list as $key => $character) { echo $key, ' ', $character, PHP_EOL; } echo PHP_EOL; 0 Ash 1 Bingo 2 Charlie 3 Delta 4 Echo

Slide 17

Slide 17 text

2 Charlie 3 Delta 4 Echo $list->rewind(); echo sprintf( "It's %s's turn! They take out %s!", $list->current(), $list[2] ), PHP_EOL; $list->offsetUnset(2); foreach ($list as $key => $character) { echo $key, ' ', $character, PHP_EOL; } echo PHP_EOL;

Slide 18

Slide 18 text

foreach ($list as $key => $character) { echo $key, ' ', $character, PHP_EOL; } echo PHP_EOL; It's Ash's turn! They take out Charlie! 0 Ash 1 Bingo 2 Delta 3 Echo

Slide 19

Slide 19 text

Data Structures SplDoublyLinkedList SplStack SplQueue SplPriorityQueue SplFixedArray SplObjectStorage SplHeap SplMaxHeap SplMinHeap

Slide 20

Slide 20 text

SplStack performance $startTime = microtime(true); $startSize = memory_get_usage(); $arrayStack = []; for ($i = 0; $i < $numItems; $i++) { array_push($arrayStack, mt_rand()); } $peakSize = memory_get_usage(); while (!empty($arrayStack)) { echo array_pop($arrayStack), ' '; } echo PHP_EOL; $startTime = microtime(true); $startSize = memory_get_usage(); $stack = new SplStack(); for ($i = 0; $i < $numItems; $i++) { $stack->push(mt_rand()); } $peakSize = memory_get_usage(); while (!$stack->isEmpty()) { echo $stack->pop(), ' '; } echo PHP_EOL; https://github.com/omnicolor/dark-corners-of-the-spl/blob/master/SplStackTest.php

Slide 21

Slide 21 text

SplStack performance Array: 2.78 seconds 32MiB Stack: 2.79 seconds 38MiB

Slide 22

Slide 22 text

Data Structures SplDoublyLinkedList SplStack SplQueue SplPriorityQueue SplFixedArray SplObjectStorage SplHeap SplMaxHeap SplMinHeap

Slide 23

Slide 23 text

Image By: Ermishin

Slide 24

Slide 24 text

SplHeap Access: O(log n) Search: O(log n) Insert: O(log n) Delete: O(log n)

Slide 25

Slide 25 text

class Character { public $name; public $initiative; public function __construct( string $name, int $init ) { $this->name = $name; $this->initiative = $init; } } https://github.com/omnicolor/dark-corners-of-the-spl/blob/master/SplHeap.php

Slide 26

Slide 26 text

class InitiativeHeap extends SplMaxHeap { public function compare($a, $b) : int { return $a->initiative - $b->initiative; } }

Slide 27

Slide 27 text

$init = new InitiativeHeap(); $init->insert(new Character('Ash', random_int(1, 30))); $init->insert(new Character('Bingo', random_int(1, 30))); $init->insert(new Character('Charlie', random_int(1, 30))); $init->insert(new Character('Echo', random_int(1, 30))); foreach ($init as $character) { echo sprintf( '%s %d', $character->name, $character->initiative ), PHP_EOL; }

Slide 28

Slide 28 text

foreach ($init as $character) { echo sprintf( '%s %d', $character->name, $character->initiative ), PHP_EOL; } Ash 30 Echo 27 Charlie 16 Bingo 12

Slide 29

Slide 29 text

SplHeap Array: 2.84 seconds 32MiB Heap: 5.20 seconds 16MiB https://github.com/omnicolor/dark-corners-of-the-spl/blob/master/SplHeapTest.php

Slide 30

Slide 30 text

Data Structures SplDoublyLinkedList SplStack SplQueue SplHeap SplMaxHeap SplMinHeap SplPriorityQueue SplFixedArray SplObjectStorage

Slide 31

Slide 31 text

SplFixedArray Access: O(1) Search: O(n) Insert: O(1) or O(n) Delete: O(n)

Slide 32

Slide 32 text

$a = [ 'foo' => 1, 'bar' => new StdClass(), 1 => null, false => true, ]; var_dump($a); array(3) { [“foo"]=>int(1) [“bar"]=>object(stdClass)#1 (0) {} [1]=>NULL [0]=>bool(true) } $b = [ 0 => 10, 2 => 22, PHP_INT_MAX => PHP_INT_MAX, ]; var_dump($b); array(3) { [0]=>int(10) [2]=>int(22) [9223372036854775807]=> int(9223372036854775807) } https://github.com/omnicolor/dark-corners-of-the-spl/blob/master/SplFixedArray.php

Slide 33

Slide 33 text

$c = new SplFixedArray(3); $c[0] = 10; $c[1] = 20; $c[2] = 42; var_dump($c); object(SplFixedArray)#2 (3) { [0]=>int(10) [1]=>int(20) [2]=>int(42) }

Slide 34

Slide 34 text

$d = new SplFixedArray(3); $d[0] = 10; $d[1] = 20; $d[2] = 42; $d[3] = 99; var_dump($d); PHP Fatal error: Uncaught RuntimeException: Index invalid or out of range in SplFixedArray.php:33 Stack trace: #0 {main} thrown in SplFixedArray.php on line 33

Slide 35

Slide 35 text

$e = new SplFixedArray(3); $e[0] = 10; $e[1] = 20; $e[2] = 42; $e->setSize(4); $e[3] = 99; var_dump($e); object(SplFixedArray)#5 (4) { [0]=>int(10) [1]=>int(20) [2]=>int(42) [3]=>int(99) }

Slide 36

Slide 36 text

SplFixedArray Array: 2.58 seconds 32MiB Fixed: 2.67 seconds 15MiB

Slide 37

Slide 37 text

Data Structures SplDoublyLinkedList SplStack SplQueue SplHeap SplMaxHeap SplMinHeap SplPriorityQueue SplFixedArray SplObjectStorage

Slide 38

Slide 38 text

Data Structures SplDoublyLinkedList SplStack SplQueue SplHeap SplMaxHeap SplMinHeap SplPriorityQueue SplFixedArray SplObjectStorage

Slide 39

Slide 39 text

$char = new Character(); $storage = []; $storage[$char] = [‘alive’ => true]; Warning: Illegal offset type in SplObjectStorage.php on line 3

Slide 40

Slide 40 text

class Character {} class Enemy {} class Buff {} class Ailment {}

Slide 41

Slide 41 text

class Buff {} class Ailment {} $fighter = new Character(); $mage = new Character(); $goblin = new Enemy(); $ogre = new Enemy(); $haste = new Buff(); $poison = new Ailment();

Slide 42

Slide 42 text

$encounter = new SplObjectStorage(); $encounter->attach($fighter, [$haste]); $encounter->attach($mage, [$haste, $poison]); $encounter[$goblin] = [$poison]; $encounter->attach($ogre); foreach ($encounter as $key => $value) { print_r($key); echo PHP_EOL; print_r($value); } $poison = new Ailment();

Slide 43

Slide 43 text

foreach ($encounter as $key => $value) { print_r($key); echo PHP_EOL; print_r($value); } 0 Character Object() 1 Character Object() 2 Enemy Object() 3 Enemy Object()

Slide 44

Slide 44 text

object(SplObjectStorage)#7 (1) { ["storage":"SplObjectStorage":private]=>array(4) { ["000000005460553e00000000545bda63"]=>array(2) { ["obj"]=>object(Character)#1 (0) {} ["inf"]=>array(1) { [0]=>object(Buff)#5 (0) {} } } } }

Slide 45

Slide 45 text

foreach ($encounter as $key) { print_r($key); print_r($encounter[$key]); }

Slide 46

Slide 46 text

print_r($encounter[$key]); } Character Object() // fighter Array( [0] => Buff Object() // haste ) Character Object() // mage Array( [0] => Buff Object() // haste [1] => Ailment Object() // poison ) Enemy Object() // goblin Array( [0] => Ailment Object() // poison ) Enemy Object()

Slide 47

Slide 47 text

–Lady Gaga “I just am committed wholeheartedly to theatre with no intermission.”

Slide 48

Slide 48 text

SPL Interfaces Countable OuterIterator RecursiveIterator SeekableIterator SplObserver SplSubject https://secure.php.net/manual/en/spl.interfaces.php

Slide 49

Slide 49 text

Countable interface Countable { public function count() : int; }

Slide 50

Slide 50 text

class Countable { public function count() : int { return 42; } } $foo = new Countable(); echo count($foo), PHP_EOL;

Slide 51

Slide 51 text

class Countable { public function count() : int { return 42; } } $foo = new Countable(); echo count($foo), PHP_EOL; Warning: count(): Parameter must be an array or an object that implements Countable in Countable.php on line 13 1

Slide 52

Slide 52 text

object that implements Countable in Countable.php on line 13 1 class ActuallyCountable implements Countable { public function count() { return 42; } } $bar = new ActuallyCountable(); echo count($bar), PHP_EOL;

Slide 53

Slide 53 text

SplSubject interface SplSubject { function attach(SplObserver $observer): void; function detach(SplObserver $observer): void; function notify(): void; }

Slide 54

Slide 54 text

SplObserver interface SplObserver { function update(SplSubject $subject): void; }

Slide 55

Slide 55 text

// ... public function attach(\SplObserver $observer): void { $this->observers->attach($observer); } class Character implements \SplSubject, \SplObserver { public $name; protected $observers; protected $message; public function __construct(string $name) { $this->name = $name; $this->observers = new \SplObjectStorage(); } // ...

Slide 56

Slide 56 text

// ... public function update(\SplSubject $subject): void { // ... public function attach(\SplObserver $observer): void { $this->observers->attach($observer); } public function detach(\SplObserver $observer): void { $this->observers->detach($observer); } public function notify(): void { foreach ($this->observers as $observer) { $observer->update($this); } } // ... } // ...

Slide 57

Slide 57 text

// ... public function sendMessage(string $message): void { $this->message = $message; $this->notify(); foreach ($this->observers as $observer) { $observer->update($this); } } // ... // ... public function update(\SplSubject $subject): void { echo sprintf( '%s received message: %s', $this->name, $subject->readMessage() ), PHP_EOL; } // ...

Slide 58

Slide 58 text

$subject->readMessage() ), PHP_EOL; } // ... } $fighter = new Character('Fighter'); $mage = new Character('Mage'); $thief = new Character('Thief'); // ... public function sendMessage(string $message): void { $this->message = $message; $this->notify(); } public function readMessage(): string { return sprintf( '%s said "%s"', $this->name, $this->message ); } }

Slide 59

Slide 59 text

return sprintf( '%s said "%s"', $this->name, $this->message ); } } } $fighter = new Character('Fighter'); $mage = new Character('Mage'); $thief = new Character('Thief'); $paladin = new Character('Paladin'); // Fighter, mage, and paladin listen to everyone else. $mage->attach($fighter); $thief->attach($fighter); $paladin->attach($fighter); $fighter->attach($mage); $thief->attach($mage); $paladin->attach($mage); $fighter->attach($paladin); $mage->attach($paladin); $thief->attach($paladin); $thief->attach($paladin);

Slide 60

Slide 60 text

// Thief doesn't pay attention to anyone else, jerk. $paladin->sendMessage( ’Get ready for a fight. Mage, can you buff us?’ ); $mage->sendMessage('Sure, give me a second.'); $fighter->sendMessage('LEEEEROY JENKINS!'); $thief->sendMessage('Dangit Fighter!'); $thief->attach($mage); $paladin->attach($mage); $fighter->attach($paladin); $mage->attach($paladin);

Slide 61

Slide 61 text

Fighter received message: Paladin said "Get ready for a fight. Mage, can you buff us?" Mage received message: Paladin said "Get ready for a fight. Mage, can you buff us?" Fighter received message: Mage said "Sure, give me a second." Paladin received message: Mage said "Sure, give me a second." Mage received message: Fighter said "LEEEEROY JENKINS!" Paladin received message: Fighter said "LEEEEROY JENKINS!" Fighter received message: Thief said "Dangit Fighter!" Mage received message: Thief said "Dangit Fighter!" Paladin received message: Thief said "Dangit Fighter!"

Slide 62

Slide 62 text

SPL Exceptions BadFunctionCallException BadMethodCallException DomainException InvalidArgumentException LengthException LogicException OutOfBoundsException OutOfRangeException OverflowException RangeException RuntimeException UnderflowException UnexpectedValueException https://secure.php.net/manual/en/spl.exceptions.php

Slide 63

Slide 63 text

SPL File Handling SplFileInfo SplFileObject SplTempFileObject https://secure.php.net/manual/en/spl.files.php

Slide 64

Slide 64 text

ArrayObject

Slide 65

Slide 65 text

Slides: https://bit.ly/2EFZsea https://twitter.com/omnicolor Omni Adams [email protected] https://joind.in/talk/7e11a https://github.com/omnicolor/dark-corners-of-the-spl When I Work