Slide 1

Slide 1 text

IPC 2013 IPC 2013 Decoupling Objects With Standard Interfaces

Slide 2

Slide 2 text

About Me About Me ● Thomas Weinert ● @ThomasWeinert ● dimensional GmbH ● papaya CMS ● PHP, Javascript, XSLT ● XML Fanatic (JSON is BAD)

Slide 3

Slide 3 text

Interfaces Interfaces ● By Declaration ● By Convention ● Magic Methods

Slide 4

Slide 4 text

Reasons Reasons ● Encapsulation ● Reuse ● S.O.L.I.D.

Slide 5

Slide 5 text

Implement Implement class Foo implements Countable, IteratorAggregate { }

Slide 6

Slide 6 text

Extend Extend interface Foo extends IteratorAggregate { }

Slide 7

Slide 7 text

Extend Extend interface Foo extends IteratorAggregate, ArrayAccess { }

Slide 8

Slide 8 text

Validate Validate if ($foo instanceOf Traversable) { }

Slide 9

Slide 9 text

Type Hints Type Hints function bar(Traversable $foo) { }

Slide 10

Slide 10 text

Interfaces Interfaces By Convention

Slide 11

Slide 11 text

Object Initialization Object Initialization ● Magic Methods ● __construct() ● __destruct() ● __clone() ● __sleep()/__wakeup() → Serializeable ● __set_state()

Slide 12

Slide 12 text

__toString __toString /** * Casting the object to string will * return the last value * @return string */ public function __toString() { return (string)end($this->_values); }

Slide 13

Slide 13 text

Dynamic Properties Dynamic Properties $object->value = 123 $value = $object->value; $object->setValue(123); $value = $object->getValue();

Slide 14

Slide 14 text

Dynamic Properties Dynamic Properties ● __isset() ● __get() ● __set() ● __unset()

Slide 15

Slide 15 text

__isset() __isset() /** * @param string $name * @return boolean */ public function __isset($name) { switch ($name) { case name : case value : case values : return TRUE; } return FALSE; }

Slide 16

Slide 16 text

__get() __get() /** * @param string $name * @throws InvalidArgumentException * @return mixed */ public function __get($name) { switch ($name) { case name : return $this->_name; case value : return end($this->_values); case values : return $this->_values; } throw new LogicException( sprintf( 'Can not read non existing property: %s::$%s', __CLASS__, $name ) ); }

Slide 17

Slide 17 text

__set() __set() /** * @param string $name * @param string|array|Traversable $value * @throws LogicException */ public function __set($name, $value) { switch ($name) { case name : $this->setName($value); return; case value : $this->setData((string)$value); return; case values : $this->setData($value); return; } throw new LogicException( sprintf( 'Can not write non existing property: %s::$%s', __CLASS__, $name ...

Slide 18

Slide 18 text

__call/__callStatic __call/__callStatic ● Dynamic Methods/Functions

Slide 19

Slide 19 text

Generic Callbacks Generic Callbacks class MyEvents extends Events { public function __construct() { parent::__construct(['example' => 21]); } } $my = new MyEvents(); echo $my->onExample(), "n"; //21 $my->onExample = function () { return 42; }; echo $my->onExample(), "n"; //42 $my->onExample = 23; echo $my->onExample(), "n"; //23

Slide 20

Slide 20 text

PHP Documentor PHP Documentor /** * … * @property Callable $onExample * @method mixed onExample() */ class MyEvents extends Events { public function __construct() { parent::__construct(['example' => 21]); } }

Slide 21

Slide 21 text

Callable Callable ● function ● array($object, method) ● function() {} ● class { public function __invoke() {} }

Slide 22

Slide 22 text

Callback Lists Callback Lists $queries = Io\Deferred::When( $mysqlOne("SELECT Query 1, SLEEP(5)")->done( function($result) use ($time) { var_dump(iterator_to_array($result)); var_dump(microtime(TRUE) - $time); } ), $mysqlTwo("SELECT Query 2, SLEEP(1)")->done( function($result) use ($time) { var_dump(iterator_to_array($result)); var_dump(microtime(TRUE) - $time); } ) );

Slide 23

Slide 23 text

Functor Example Functor Example class DatabaseResultDebugger { private $_startTime = 0; public function __construct($startTime) { $this->_startTime = $startTime; } public function __invoke($result) { var_dump(iterator_to_array($result)); var_dump( microtime(TRUE) - $this->_startTime ); } }

Slide 24

Slide 24 text

Callback Handlers Callback Handlers $queries = Io\Deferred::When( $mysqlOne("SELECT Query 1, SLEEP(5)")->done( new DatabaseResultDebugger($time) ), $mysqlTwo("SELECT Query 2, SLEEP(1)")->done( new DatabaseResultDebugger($time) ) );

Slide 25

Slide 25 text

More Callback Handlers More Callback Handlers $queries = Io\Deferred::When( $mysqlOne("SELECT Query 1, SLEEP(5)") ->done( new ConcreteDatabaseResultHandler() ) ->done( new DatabaseResultDebugger($time) ), $mysqlTwo("SELECT Query 2, SLEEP(1)") ->done( new DatabaseResultDebugger($time) ) );

Slide 26

Slide 26 text

Predeclared Interfaces Predeclared Interfaces ● Serializeable ● Usage ● serialize($object) ● unserialize($string); ● Methods ● $object->serialize() ● $object->unserialize($string);

Slide 27

Slide 27 text

JsonSerializable JsonSerializable ● Usage ● json_encode() ● Method ● $object->jsonSerialize()

Slide 28

Slide 28 text

ArrayAccess ArrayAccess ● [] -Syntax ● Validation ● Conversion ● Lazy Initialization

Slide 29

Slide 29 text

ArrayAccess Methods ArrayAccess Methods ● offsetExists() ● offsetGet() ● offsetSet() ● offsetUnset()

Slide 30

Slide 30 text

OffsetExists() OffsetExists() /** * @param integer $offset * @return boolean */ public function offsetExists($offset) { return array_key_exists( $offset, $this->_values ); }

Slide 31

Slide 31 text

OffsetGet() OffsetGet() /** * @param integer $offset */ public function offsetGet($offset) { return $this->_values[$offset]; }

Slide 32

Slide 32 text

OffsetSet() OffsetSet() /** * @param integer $offset * @param string $value */ public function offsetSet($offset, $value) { if (NULL === $offset) { $this->_values[] = $value; } else { $this->_values[$offset] = $value; } }

Slide 33

Slide 33 text

OffsetUnset() OffsetUnset() /** * @param integer $offset */ public function offsetUnset($offset) { unset($this->_values[$offset]); }

Slide 34

Slide 34 text

Array Dereferencing Array Dereferencing echo $object->foo()[0];

Slide 35

Slide 35 text

Countable Countable ● Usage ● count($foo) ● Method ● count()

Slide 36

Slide 36 text

Countable Example Countable Example class DatabaseResult implements Countable { ... public function count() { return $this->_count; } ... }

Slide 37

Slide 37 text

Traversable Traversable ● Usage ● foreach($traversable as $key=>$value) ● Implementations ● Iterator ● IteratorAggregate

Slide 38

Slide 38 text

Iterator Interfaces Iterator Interfaces Traversable IteratorAggregate Iterator SeekableIterator RecursiveIterator OuterIterator SPL

Slide 39

Slide 39 text

Iterator functions - Usage Iterator functions - Usage ● foreach() ● iterator_to_array() ● iterator_count() ● iterator_apply()

Slide 40

Slide 40 text

Iterator Implementation Iterator Implementation ● rewind() ● next() ● valid() ● current() ● key()

Slide 41

Slide 41 text

IteratorAggregate IteratorAggregate ● getIterator() class MyDatabaseResult implements IteratorAggregate { private $_items = array(); public function getIterator() { return new ArrayIterator( $this->_items ); } }

Slide 42

Slide 42 text

Predefined Iterators Predefined Iterators ● ArrayIterator ● EmptyIterator ● RegexIterator ● …

Slide 43

Slide 43 text

Nest Iterators Nest Iterators ● IteratorIterator ● AppendIterator ● CallbackFilterIterator ● ...

Slide 44

Slide 44 text

RecursiveIterator RecursiveIterator ● List with Children $items = [ 1 => '1', 2 => '1.1', 3 => '2' ]; $structure = [ 0 => [1, 3], 1 => [2] ];

Slide 45

Slide 45 text

Inherit from IteratorIterator Inherit from IteratorIterator class Bar extends IteratorIterator implements RecursiveIterator { private $_items = []; private $_structure = []; public function __construct( $items, $structure, $parent = 0 ) { → next slide } …

Slide 46

Slide 46 text

Inherit from IteratorIterator Inherit from IteratorIterator … $siblings = []; if (!empty($structure[$parent])) { foreach ($structure[$parent] as $id) { if (isset($items[$id])) { $siblings[$id] = $items[$id]; } } } parent::__construct( new ArrayIterator($siblings) ); $this->_items = $items; $this->_structure = $structure; …

Slide 47

Slide 47 text

hasChildren() hasChildren() public function hasChildren() { return $this->valid() && isset( $this->_structure[$this->key()] ); }

Slide 48

Slide 48 text

getChildren() getChildren() public function getChildren() { if ($this->hasChildren()) { return new $this( $this->_items, $this->_structure, $this->key() ); } else { return new $this([], []); } }

Slide 49

Slide 49 text

RecursiveIteratorIterator RecursiveIteratorIterator ● Iterator for RecursiveIterator $iterator = new RecursiveIteratorIterator( new Bar($items, $structure), RecursiveIteratorIterator::SELF_FIRST ); foreach ($iterator as $element) { echo str_repeat(*, $iterator->getDepth() + 1); echo $element; echo "n"; }

Slide 50

Slide 50 text

Result Result * 1 ** 1.1 * 2 ● No recursive function call ● Works with Traversable/ArrayAccess ● Allows for Lazy Initalization

Slide 51

Slide 51 text

Thank You Thank You ● Questions? ● Twitter: @ThomasWeinert ● Blog: http://a-basketful-of-papayas.net