diff --git a/src/Prototype.php b/src/Prototype.php index b79798b..9fc8646 100644 --- a/src/Prototype.php +++ b/src/Prototype.php @@ -3,6 +3,7 @@ class Prototype implements \ArrayAccess { private $drivers = array(); + private $events = array(); final public function extend($name, $callable) { @@ -14,17 +15,59 @@ final public function hasDriver($name) return isset($this->drivers[$name]); } + final public function on($name, $callable, $weights = 0) + { + $weights = (int) $weights; + $this->events[$name][$weights][] = $callable; + + return $this; + } + + private function fetchEvent($name, $timing) + { + return isset($this->events["{$name}.{$timing}"]) ? + $this->events["{$name}.{$timing}"] : + array(); + } + + private function fireEvent($name, $timing, $payload = array()) + { + $events_list = $this->fetchEvent($name, $timing); + ! empty($events_list) and krsort($events_list); + foreach ($events_list as $events) { + foreach ($events as $event) { + if (false === $event($payload)) { + return; + } + } + } + } + final public function __call($name, $args) { if ($this->hasDriver($name)) { + $payload = $args; array_unshift($args, $this); - return \Rde\call($this->drivers[$name], $args); + $this->fireEvent($name, 'before', $payload); + $ret = \Rde\call($this->drivers[$name], $args); + $this->fireEvent($name, 'after', $payload); + + return $ret; } throw new \BadMethodCallException("沒有安裝[{$name}]處理驅動"); } + public function __toString() + { + if ($this->hasDriver('__toString')) { + return $this->__call('__toString', array()); + } + + return '['.get_called_class().']'; + } + final public function offsetExists($key) { return isset($this->drivers[$key]); diff --git a/tests/PrototypeTest.php b/tests/PrototypeTest.php index 3ca3588..6ad05aa 100644 --- a/tests/PrototypeTest.php +++ b/tests/PrototypeTest.php @@ -70,4 +70,52 @@ public function testException() $o->getColde(); } + + public function testEventWeight() + { + $tester = $this; + $o = new Rde\Prototype(); + $event_cnt = 0; + + // 期望順序: 2 + $o->on('test.before', function($payload) use($tester, &$event_cnt){ + ++$event_cnt; + $tester->assertEquals(array(99), $payload, '檢查參數傳遞'); + $tester->assertEquals(2, $event_cnt, '檢查呼叫順序'); + return 7; + }, 7); + + // 期望順序: 3 + $o->on('test.before', function($payload) use($tester, &$event_cnt){ + ++$event_cnt; + $tester->assertEquals(3, $event_cnt, '檢查呼叫順序'); + }, 7); + + // 期望順序: 1 + $o->on('test.before', function($payload) use($tester, &$event_cnt){ + ++$event_cnt; + $tester->assertEquals(1, $event_cnt, '檢查呼叫順序'); + }, 9); + + $o->extend('test', function($self, $arg){}); + + $o->test(99); + + $this->assertEquals(3, $event_cnt, '檢查事件是否全執行'); + } + + public function testToString() + { + $o = new Rde\Prototype(); + + $this->assertEquals('['.get_class($o).']', (string) $o, '檢查預設轉型(string)'); + + $str = 'hello world'; + $o->extend('__toString', function() use($str){ + return $str; + }); + + $this->assertEquals($str, (string) $o, '檢查自訂轉型(string)'); + + } }