IPC 2013: Decoupling Objects With Standard Interfaces

IPC 2013: Decoupling Objects With Standard Interfaces

3f2fb8bbcd44609346e1cc0c06d0a39b?s=128

Thomas Weinert

October 30, 2013
Tweet

Transcript

  1. IPC 2013 IPC 2013 Decoupling Objects With Standard Interfaces

  2. About Me About Me • Thomas Weinert • @ThomasWeinert •

    dimensional GmbH • papaya CMS • PHP, Javascript, XSLT • XML Fanatic (JSON is BAD)
  3. Interfaces Interfaces • By Declaration • By Convention • Magic

    Methods
  4. Reasons Reasons • Encapsulation • Reuse • S.O.L.I.D.

  5. Implement Implement class Foo implements Countable, IteratorAggregate { }

  6. Extend Extend interface Foo extends IteratorAggregate { }

  7. Extend Extend interface Foo extends IteratorAggregate, ArrayAccess { }

  8. Validate Validate if ($foo instanceOf Traversable) { }

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

  10. Interfaces Interfaces By Convention

  11. Object Initialization Object Initialization • Magic Methods • __construct() •

    __destruct() • __clone() • __sleep()/__wakeup() → Serializeable • __set_state()
  12. __toString __toString /** * Casting the object to string will

    * return the last value * @return string */ public function __toString() { return (string)end($this->_values); }
  13. Dynamic Properties Dynamic Properties $object->value = 123 $value = $object->value;

    $object->setValue(123); $value = $object->getValue();
  14. Dynamic Properties Dynamic Properties • __isset() • __get() • __set()

    • __unset()
  15. __isset() __isset() /** * @param string $name * @return boolean

    */ public function __isset($name) { switch ($name) { case name : case value : case values : return TRUE; } return FALSE; }
  16. __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 ) ); }
  17. __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 ...
  18. __call/__callStatic __call/__callStatic • Dynamic Methods/Functions

  19. 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
  20. PHP Documentor PHP Documentor /** * … * @property Callable

    $onExample * @method mixed onExample() */ class MyEvents extends Events { public function __construct() { parent::__construct(['example' => 21]); } }
  21. Callable Callable • function • array($object, method) • function() {}

    • class { public function __invoke() {} }
  22. 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); } ) );
  23. 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 ); } }
  24. 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) ) );
  25. 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) ) );
  26. Predeclared Interfaces Predeclared Interfaces • Serializeable • Usage • serialize($object)

    • unserialize($string); • Methods • $object->serialize() • $object->unserialize($string);
  27. JsonSerializable JsonSerializable • Usage • json_encode() • Method • $object->jsonSerialize()

  28. ArrayAccess ArrayAccess • [] -Syntax • Validation • Conversion •

    Lazy Initialization
  29. ArrayAccess Methods ArrayAccess Methods • offsetExists() • offsetGet() • offsetSet()

    • offsetUnset()
  30. OffsetExists() OffsetExists() /** * @param integer $offset * @return boolean

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

    offsetGet($offset) { return $this->_values[$offset]; }
  32. OffsetSet() OffsetSet() /** * @param integer $offset * @param string

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

    offsetUnset($offset) { unset($this->_values[$offset]); }
  34. Array Dereferencing Array Dereferencing echo $object->foo()[0];

  35. Countable Countable • Usage • count($foo) • Method • count()

  36. Countable Example Countable Example class DatabaseResult implements Countable { ...

    public function count() { return $this->_count; } ... }
  37. Traversable Traversable • Usage • foreach($traversable as $key=>$value) • Implementations

    • Iterator • IteratorAggregate
  38. Iterator Interfaces Iterator Interfaces Traversable IteratorAggregate Iterator SeekableIterator RecursiveIterator OuterIterator

    SPL
  39. Iterator functions - Usage Iterator functions - Usage • foreach()

    • iterator_to_array() • iterator_count() • iterator_apply()
  40. Iterator Implementation Iterator Implementation • rewind() • next() • valid()

    • current() • key()
  41. IteratorAggregate IteratorAggregate • getIterator() class MyDatabaseResult implements IteratorAggregate { private

    $_items = array(); public function getIterator() { return new ArrayIterator( $this->_items ); } }
  42. Predefined Iterators Predefined Iterators • ArrayIterator • EmptyIterator • RegexIterator

    • …
  43. Nest Iterators Nest Iterators • IteratorIterator • AppendIterator • CallbackFilterIterator

    • ...
  44. RecursiveIterator RecursiveIterator • List with Children $items = [ 1

    => '1', 2 => '1.1', 3 => '2' ]; $structure = [ 0 => [1, 3], 1 => [2] ];
  45. 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 } …
  46. 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; …
  47. hasChildren() hasChildren() public function hasChildren() { return $this->valid() && isset(

    $this->_structure[$this->key()] ); }
  48. getChildren() getChildren() public function getChildren() { if ($this->hasChildren()) { return

    new $this( $this->_items, $this->_structure, $this->key() ); } else { return new $this([], []); } }
  49. 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"; }
  50. Result Result * 1 ** 1.1 * 2 • No

    recursive function call • Works with Traversable/ArrayAccess • Allows for Lazy Initalization
  51. Thank You Thank You • Questions? • Twitter: @ThomasWeinert •

    Blog: http://a-basketful-of-papayas.net