_inner = $inner; } public function inject_before_call($pattern, $method_name) { $this->_before[] = array("/".$pattern."/", $method_name); } public function inject_after_call($pattern, $method_name) { $this->_after[] = array("/".$pattern."/", $method_name); } private function __call($method_name, $params) { foreach ($this->_before as $lookup) { list($pattern, $before_method_name) = $lookup; if (preg_match($pattern, $method_name)) { call_user_method_array($before_method_name, $this, array($method_name, $params)); } } $result = call_user_method_array($method_name, $this->_inner, $params); foreach ($this->_after as $lookup) { list($pattern, $after_method_name) = $lookup; if (preg_match($pattern, $method_name)) { call_user_method_array($after_method_name, $this, array($method_name, $params, $result)); } } return $result; } } /** * Provides logging at the beginning of a method invocation, and when the method * returns */ class LogAdvice extends AOP { public function __construct($obj) { AOP::__construct($obj); $this->inject_before_call(".*", "log_start"); $this->inject_after_call(".*", "log_end"); } public function log_start($method_name, $params) { echo "START: {$method_name}\n"; } public function log_end($method_name, $params, $result) { echo "END: {$method_name}\n"; } } class TimingAdvice extends AOP { private $_clock_times = array(); // Stack used for clock ticks public function __construct($obj) { AOP::__construct($obj); $this->inject_before_call(".*", "begin_timing"); $this->inject_after_call(".*", "end_timing"); } public function begin_timing($method_name, $params) { array_push($this->_clock_times, microtime()); } public function end_timing($method_name, $params, $result) { $start_time = array_pop($this->_clock_times); $end_time = microtime(); $duration = round(($end_time - $start_time)*1000, 5); echo "{$method_name} took {$duration}ms\n"; } } class TestObj { public function test1() { echo "Test1 Called\n"; } public function test2() { echo "Test2 Called\n"; } } // The gluing together of objects would be done by the container (as in the Spring Framework) // So even though the next line is ugly, you'll note that the TestObj class above remains simple. $test = new TimingAdvice(new LogAdvice(new TestObj())); $test->test1(); $test->test2(); ?>