iterators, arrayaccess & countable (oh my!) - madison php 2014

46
By: Sandy Smith (originally by Eli White) CEO & Founding Partner: musketeers.me Training Director: phparch.com @SandyS1 – Oh My! Iterators, ArrayAccess & Countable

Upload: sandy-smith

Post on 01-Dec-2014

327 views

Category:

Software


1 download

DESCRIPTION

Learn how to empower your objects in PHP with SPL! The SPL (Standard PHP Library) has existed for many years but is still one of the less understood parts of the language. We will cover some of the most useful core aspects of the SPL, features that are easy to add to your own objects, making them more powerful and flexible!

TRANSCRIPT

Page 1: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

By: Sandy Smith (originally by Eli White) CEO & Founding Partner: musketeers.me Training Director: phparch.com

!!

@SandyS1

– Oh My! Iterators, ArrayAccess & Countable

Page 2: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

1st: The SPL (Standard PHP Library)

!A standard set of interfaces & classes for PHP5

!Designed to solve standard problems

and provide efficient data access.

2

Page 3: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

SPL Features

!

SPL includes numerous types of features: - Data Structures (Linked Lists, Stacks, Queues, Heaps, …)

- Iterators (w/ Filtering, Caching, Recursion, …)- Various standard objects (FileObject, ArrayObject, …)

- Subject/Observer Interface - Exceptions- and more …

3

Page 4: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

This talk …

4

!

Will focus on a core set that are generically

useful for all your data access objects.

!Iterators, ArrayAccess, Countable

!(and maybe a few others)

Page 5: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Why?

5

!Allows your user-space objects to be treated like native 1st class types.

Page 6: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Starting us offYou have to start from somewhere …!

6

Page 7: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Features we want to duplicate

All features built in to arrays !

foreach iteration: foreach ($array as $key => $value) { echo "{$key}: {$value}\n"; }

!

direct item access: echo $array[5];

!

countability: echo count($array);

7

Page 8: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

A Basic Class

8

class Set { protected $_set; public function __construct(Array $parameters = NULL) { $this->_set = $this->_loadFromCache($parameters); if ($this->_set === NULL) { $this->_set = $this->_loadFromDatabase($parameters); } if ($this->_set === NULL) { $this->_set = []; } } protected function _loadFromCache(Array $parameters = NULL) { // Pull data from cache, returning an array of arrays or objects } protected function _loadFromDatabase(Array $parameters = NULL) { // Pull data from DB, returning an array of arrays or objects } }

Page 9: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

But you need to access the data…

9

class SetAccess extends Set { public function getAll() { return $this->_set; } public function get($index) { if (array_key_exists($index, $this->_set)) { return $this->_set[$index]; } else { return NULL; } } }

!

So you need to implement some access method:

Page 10: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Inelegant solution

10

!Leaves you accessing data in these ways:$myset = new SetAccess(); print_r($myset->get(3));

!$myset = new SetAccess(); $all = $myset->getAll(); foreach ($all as $item) { print_r($item); }

Page 11: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

IteratorsNatively use foreach on your objects

11

Page 12: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Iterator Interface

12

interface Iterator extends Traversable { 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 ) }

!

5 methods to define, revolve around remembering state: current(): Returns the current value key(): Returns the current value’s access key next(): Moves the internal pointer to the next item rewind(): Needs to reset the internal pointer to the first item

valid(): Returns whether the internal pointer is at a valid data item

Page 13: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Easy to implement with Arrays

13

class SetIteratable extends SetAccess implements Iterator { public function current() { return current($this->_set); } public function key() { return key($this->_set); } public function next() { next($this->_set); } public function rewind() { reset($this->_set); } public function valid() { return (key($this->_set) !== NULL); } }

Page 14: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Now have direct access…

14

$myset = new SetIteratable(); foreach ($myset as $key => $item) { echo "{$key}: ", print_r($item, true), "<br/>\n"; }

!Now we can access the object directly in a foreach loop!

Page 15: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

ArrayAccessTreat your object like it was an array.

15

Page 16: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

ArrayAccess Interface

16

interface ArrayAccess { abstract public boolean offsetExists ( mixed $offset ) abstract public mixed offsetGet ( mixed $offset ) abstract public void offsetSet ( mixed $offset , mixed $value ) abstract public void offsetUnset ( mixed $offset ) }

!4 methods to define, to gain direct key access:

offsetExists(): Does the provided key exist? offsetGet(): Return the value at provided key offsetSet(): Set the value at the provided key offsetUnset(): Remove the value (and key) provided

Page 17: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Again easy to code with builtins …

17

class SetArray extends SetIteratable implements ArrayAccess { public function offsetExists($offset) { return array_key_exists($offset, $this->_set); } public function offsetGet($offset) { return $this->_set[$offset]; } public function offsetSet($offset, $value) { if (is_null($offset)) { $this->_set[] = $value; } else { $this->_set[$offset] = $value; } } public function offsetUnset($offset) { unset($this->_set[$offset]); } }

Page 18: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Treat it like an array…

18

!You can now directly treat the object like an array:

$myset = new SetArray(); print_r($myset[3]); if (isset($myset['Sandy'])) { echo “Smith"; } $myset['Eli'] = 'White'; echo '<p>', $myset['Eli'], '</p>'; unset($myset['Eli']); $myset[] = [2013, 2014, 2015]; $myset[] = 'php[tek] 2015';

!NOTE: You don’t have to implement everything. Create blank offsetSet() and offsetUnset() if you don’t want to allow modification!

Page 19: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

CountableAnd while we are at it …

19

Page 20: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Countable Interface

20

!Just one method:

count(): How many items in this object?

class SetCountable extends SetArray implements Countable { public function count() { return count($this->_set); } } $myset = new SetCountable(); echo count($myset);

Page 21: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Return whatever you want though…

21

!

Like all these, what you return is up to you!

class SetCountable extends SetArray implements Countable { public function count() { return count($this->_set, COUNT_RECURSIVE); } } $myset = new SetCountable(); echo count($myset);

Page 22: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

SerializableAnother bit of magic…

22

Page 23: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Serializable Interface

23

!2 methods to let you custom define serialization:

serialize(): Returns a serialized form of your object unserialize(): Instantiates an object, given the serialized form

interface Serializable { abstract public string serialize ( void ) abstract public void unserialize ( string $serialized ) }

Page 24: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

A simple example, just saving data

24

class SetSerial extends SetArray implements Serializable { public function serialize() { return serialize($this->_set); } public function unserialize($serialized) { $this->_set = unserialize($serialized); } }

!

Simple, and serialization works as normal!

$myset = new SetSerial(); $myset['magazine'] = ‘php[architect]’; $save = serialize($myset); $restore = unserialize($save); echo $restore['magazine'];

Page 25: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

But you can return whatever…

25

!Only save what data you want.

Encode in whatever format you want:

class SetSerialFunky extends SetArray implements Serializable { public function serialize() { $copy = array_filter($this->_set, function ($val) { return !is_array($val); }); return json_encode($copy); } public function unserialize($serialized) { $this->_set = json_decode($serialized, TRUE); } }

Page 26: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Putting it all togetherSo what does this look like…!

26

Page 27: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Put it all together and what do we get?

27

class SetFull implements Iterator, ArrayAccess, Countable, Serializable { // Iterator: public function current() { return current($this->_set); } public function key() { return key($this->_set); } public function next() { next($this->_set); } public function rewind() { reset($this->_set); } public function valid() { return (key($this->_set) !== NULL); } // ArrayAccess: public function offsetExists($key) { return array_key_exists($key, $this->_set); } public function offsetGet($key) { return $this->_set[$key]; } public function offsetUnset($key) { unset($this->_set[$key]); } public function offsetSet($key, $value) { if (is_null($key)) { $this->_set[] = $value; } else { $this->_set[$key] = $value; } } // Countable: public function count() { return count($this->_set); } // Serializable public function serialize() { return serialize($this->_set); } public function unserialize($data) { $this->_set = unserialize($data); } }

Page 28: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Get creative!

28

!This only scrapes the surface of what is possible!

!

None of the methods need to

return ‘basic’ information like this.

!Get as creative as needed for your situation!

Page 29: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Bonus Round!Let’s look at some magic methods…!

29

Page 30: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Magic methods have come a long way…

30

!Not just your __get & __set anymore!

!

Let’s look at some PHP5 magic methods

that are useful to data access classes!

Page 31: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

__toString()

31

!Been around a while, but recently become universal

class SetString extends SetSerial { public function __toString() { return "Set: " . print_r($this->_set, TRUE); } } !$myset = new SetString(); echo $myset;

Page 32: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

__set_state()

32

!

Called statically by var_export() on your object: IE: var_export returns: SetState::__set_state($data);

class SetState extends SetString { public static function __set_state(Array $array) { $obj = new self(); $obj->_set = $array['_set']; return $obj; } } $myset = new SetState(); $export = var_export($myset, TRUE); eval('$newset = '. $export. ';'); echo $newset;

Page 33: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

__callStatic()

33

!__call() has been around for a while to dynamic method calls.__callStatic() now allows the same feature on static methods.

class SetCall extends SetState { public function __call($name, $args) { if ($name == 'flip') { return array_reverse($this->_set); } } public function __callStatic($name, $args) { if ($name == 'factory') { return new self(); } } } $myset = SetCall::factory(); $reversed = $myset->flip(); var_dump($reversed);

Page 34: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

__invoke()

34

!

Blow your mind: Allows your object to be called as a function!

class SetInvoke extends SetCall { public function __invoke($start, $length) { return array_slice($this->_set, $start, $length, TRUE); } } $myset = new SetInvoke(); $slice = $myset(1,3); var_dump($slice);

!Can do anything with this!

Page 35: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

More Iterator Fun!If we have time, let’s play!!

35

Page 36: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

InfiniteIterator

36

!Causes an iterator to automatically rewind:

$forever = new InfiniteIterator(new SetFull()); $count = 100; foreach ($forever as $item) { print_r($item); if (!($count--)) break; }

Page 37: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

LimitIterator

37

!Allows you to set a start index & max iterations:

foreach (new LimitIterator(new SetFull(), 0, 3) as $item) { print_r($item); }

$forever = new InfiniteIterator(new SetFull()); foreach (new LimitIterator($forever, 0, 100) as $item) { print_r($item); }

Page 38: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

FilterIterator

38

!Apply your own filtering to what items are returned

class ArrayFilter extends FilterIterator { public function accept() { return is_array($this->getInnerIterator()->current()); } } foreach (new ArrayFilter(new SetFull()) as $item) { print_r($item); }

Page 39: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

RegexIterator

39

!

Predefined instance of FilterIterator with regex

$regex = new RegexIterator(new SetFull(), '/^tek[0-9]+/', RegexIterator::MATCH); foreach ($regex as $item) { print_r($item); } !Lots of options/flags: RegexIterator::MATCH RegexIterator::GET_MATCH RegexIterator::ALL_MATCHES RegexIterator::SPLIT RegexIterator::REPLACE RegexIterator::USE_KEY

Page 40: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

MultipleIterator

40

!

Allows iterating over multiple iterators at once

$multiple = new MultipleIterator(); $multiple->attachIterator(new SetFull()); $multiple->attachIterator(new SetFull(['other','parameters'])); foreach ($multiple as $both) { $setOne = print_r($both[0], TRUE); $setTwo = print_r($both[1], TRUE); echo "One: {$setOne} | Two: {$setTwo} <br/>\n"; }

!Stops whenever any one runs out of items

Page 41: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

RecursiveIterator & RecursiveIteratorIterator

41

class SetRecursable extends SetFull implements RecursiveIterator { public function hasChildren() { return is_array(current($this->_set)); } public function getChildren() { return new RecursiveArrayIterator(current($this->_set)); } } foreach (new RecursiveIteratorIterator(new SetRecursable()) as $item) { echo " {$item} "; }

!2 methods to you define to allow recursion:

hasChildren(): Does the current item have any children? getChildren(): If so, return a RecursiveIterator to iterate them.

Page 42: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

And so much more…

42

!SeekableIterator

!ParentIterator

!AppendIterator

!ArrayIterator !

CachingIterator

!CallbackFilterIterator

!DirectoryIterator !EmptyIterator

!FilesystemIterator

!GlobIterator

!NoRewindIterator

!RecursiveCachingIterator !

RecursiveFilterIterator

!

RecursiveDirectoryIterator

!RecursiveCallbackFilterIterator

!RecursiveRegexIterator

!RecursiveTreeIterator

Page 43: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Brief Commercial Interruption…

43

Page 44: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Get a discount to php[world]!

44

Page 45: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Win an ElePHPant!

45

Drop your card/name & email in the shoebox at our table

Page 46: Iterators, ArrayAccess & Countable (Oh My!) - Madison PHP 2014

php[architect]: http://phparch.com/   musketeers: http://musketeers.me/

Iterators, ArrayAccess & Countable, Oh My! - Sandy Smith - Madison PHP - September 13, 2014

Questions?

Twitter: @SandyS1, @phparch

Rate me: https://joind.in/11744!!!!!

46