Aspect Oriented PHP





7
Date Submitted Fri. Jun. 1st, 2007 7:30 PM
Revision 1 of 1
Helper albud
Tags aspects | design | PHP
Comments 3 comments
A proof of concept idea I had for implementing an aspect oriented framework in PHP (yes, I know about http://aophp.net, but it requires a module).

I thought it was neat, so I'm going to share it.

Hope someone likes it.

<?php
/**
 * The core AOP class
 */

 class AOP {
        private $_inner;
        private $_before = array();
        private $_after = array();
        
        public function __construct($inner) {
               $this->_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();
?>
 

Allain Lalonde

Comments

Comments PHP-AOP Framework
Wed. Jun. 20th, 2007 8:31 AM    Newbie Fairline32
  Comments Sure
Wed. Jun. 27th, 2007 9:41 PM    Helper albud
    Comments AOP conversation
Fri. Jun. 29th, 2007 3:10 PM    Newbie Fairline32

Voting