Date post: | 25-May-2015 |
Category: |
Technology |
Upload: | thomas-weinert |
View: | 304 times |
Download: | 1 times |
IPC Spring 2013IPC Spring 2013
Decoupling Objects WithStandard Interfaces
About MeAbout Me● Thomas Weinert
● papaya Software GmbH● papaya CMS
● Twitter: @ThomasWeinert● Web: http://www.a-basketful-of-papayas.net
InterfacesInterfaces● By Declaration● By Convention
● Magic Methods
ReasonsReasons● Encapsulation● Reuse● S.O.L.I.D.
ImplementImplement
class Foo implements Countable, IteratorAggregate { }
ExtendExtend
interface Foo extends IteratorAggregate { }
ValidateValidate
if ($foo instanceOf Traversable) { }
Type HintsType Hints
function bar(Traversable $foo) { }
InterfacesInterfaces
By Convention
Object InitializationObject Initialization● Magic Methods
● __construct()● __destruct()● __clone()● __sleep()/__wakeup() → Serializeable● __set_state()
__toString__toString● Cast an object to string
/** * Casting the object to string will *return the last value * @return string */public function __toString() { return (string)end($this->_values);}
Dynamic PropertiesDynamic Properties● $object->value = 123● $value = $object->value;● $object->setValue(123);● $value = $object->getValue();
Dynamic PropertiesDynamic Properties● __isset()● __get()● __set()● __unset()
__isset()__isset() /** * @param string $name * @return boolean */ public function __isset($name) { switch ($name) { case 'name' : case 'value' : case 'values' : return TRUE; } return FALSE; }
__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 ) );}
__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 ...
__call/__callStatic__call/__callStatic
Dynamic Methods/Functions
Generic CallbacksGeneric Callbacksclass 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
PHP DocumentorPHP Documentor/* * … * * @property Callable $onExample * @method mixed onExample() */class MyEvents extends Events {
public function __construct() { parent::__construct(['example' => 21]); }}
CallableCallable● 'function'● array($object, 'method')● function() {}● class {}
__invoke__invoke● Functors
● Callable
Callback ListsCallback 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); } ));
Functor ExampleFunctor 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); }}
Callback HandlersCallback 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) ));
More Callback HandlersMore 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) ));
Predeclared Interfaces
SerializeableSerializeable● Usage
● serialize($object)● unserialize($string);
● Methods● $object->serialize()● $object->unserialize($string);
JsonSerializableJsonSerializable● Usage
● json_encode()
● Method● $object->jsonSerialize()
ArrayAccessArrayAccess● [] -Syntax● Validation● Conversion● Lazy Initialization
ArrayAccess MethodsArrayAccess Methods● offsetExists()● offsetGet()● offsetSet()● offsetUnset()
OffsetExists()OffsetExists()
/** * @param integer $offset * @return boolean */ public function offsetExists($offset) { return array_key_exists($offset, $this->_values); }
OffsetGet()OffsetGet()
/** * @param integer $offset */ public function offsetGet($offset) { return $this->_values[$offset]; }
OffsetSet()OffsetSet()
/** * @param integer $offset * @param string $value */ public function offsetSet($offset, $value) { if (NULL === $offset) { $this->_values[] = $value; } else { $this->_values[$offset] = $value; } }
OffsetUnset()OffsetUnset()
/** * @param integer $offset */ public function offsetUnset($offset) { unset($this->_values[$offset]); }
Array DereferencingArray Dereferencing
echo $object->foo()[0];
CountableCountable● count($foo)
class DatabaseResult implements Countable { ... public function count() { return $this->_count; } ...}
TraversableTraversable● foreach● Iterator● IteratorAggregate
Iterator InterfacesIterator Interfaces
Traversable
Iterator
OuterIterator
IteratorAggregate
RecursiveIteratorSeekableIterator
SPL
Iterator functionsIterator functions● foreach() ● iterator_to_array()● iterator_count()● iterator_apply()
IteratorIterator● rewind()● next()● valid()● current()● key()
IteratorAggregateIteratorAggregate● getIterator()
class Foo implements IteratorAggregate { private $_items = array(); public function __construct(array $items) { $this->_items = $items; } public function getIterator() { return new ArrayIterator($this->_items); }}
Predefined IteratorsPredefined Iterators● ArrayIterator● EmptyIterator● RegexIterator● …
Nest IteratorsNest Iterators● IteratorIterator
● AppendIterator● CallbackFilterIterator● ...
RecursiveIteratorRecursiveIterator● List with Children
$items = [ 1 => '1', 2 => '1.1', 3 => '2'];
$structure = [ 0 => [1, 3], 1 => [2]];
Inherit from IteratorIteratorInherit from IteratorIteratorclass Bar extends IteratorIterator implements RecursiveIterator {
private $_items = []; private $_structure = [];
public function __construct($items, $structure, $parent = 0) { $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; }...
hasChildren()hasChildren()
public function hasChildren() { return $this->valid() && isset($this->_structure[$this->key()]); }
getChildren()getChildren()
public function getChildren() { if ($this->hasChildren()) { return new $this( $this->_items, $this->_structure, $this->key() ); } else { return new $this([], []); } }
RecursiveIteratorIteratorRecursiveIteratorIterator● 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";}
ResultResult* 1
** 1.1
* 2
● No recursive function call● Works with Traversable/ArrayAccess● Allows for Lazy Initalization
ObserverObserver
Subject
Observer 2 Observer 2Observer 2
ObserverObserver
CMS Page published
Log Action Announce ToWebservice
Invalidate Cache
ObserverObserver● SplObserver
● update()
● SplSubject● attach()● detach()● notify()
Thank YouThank You
● Twitter: @ThomasWeinert
● https://joind.in/8807