Created
August 16, 2014 18:53
-
-
Save jm42/e9fda32bc1ff0f818c30 to your computer and use it in GitHub Desktop.
Aspect Stub
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class Wallet { | |
protected $balance; | |
public function __construct($initial=0.0) { | |
$this->balance = $initial; | |
} | |
public function add($money) { | |
$this->balance += $money; | |
} | |
public function getBalance() { | |
return $this->balance; | |
} | |
} | |
############################################################################## | |
class Invocation { | |
public $instance; | |
public $method; | |
public $args; | |
public function __construct($instance, \ReflectionMethod $method, array $args) { | |
$this->instance = $instance; | |
$this->method = $method; | |
$this->args = $args; | |
} | |
public function getParam($index) { | |
return $this->args[$index]; | |
} | |
public function proceed() { | |
return $this->method->invokeArgs($this->instance, $this->args); | |
} | |
} | |
interface Pointcut { | |
function matchesClass(\ReflectionClass $class); | |
function matchesMethod(\ReflectionMethod $method); | |
} | |
interface Advice { | |
function before(Invocation $invocation); | |
function after(Invocation $invocation); | |
} | |
interface Aspect { | |
function getPointcut(); | |
function getAdvice(); | |
} | |
############################################################################## | |
class WalletPointcut implements Pointcut { | |
public function matchesClass(\ReflectionClass $class) { | |
return $class->getName() === 'Wallet'; | |
} | |
public function matchesMethod(\ReflectionMethod $method) { | |
return $method->getName() === 'add'; | |
} | |
} | |
class WalletAdvice implements Advice { | |
public function before(Invocation $invocation) { | |
echo 'ADD ' . $invocation->getParam(0) . | |
' to ' . $invocation->instance->getBalance() . PHP_EOL; | |
} | |
public function after(Invocation $invocation) {} | |
} | |
class WalletAspect implements Aspect { | |
public function getPointcut() { | |
return new WalletPointcut(); | |
} | |
public function getAdvice() { | |
return new WalletAdvice(); | |
} | |
} | |
############################################################################## | |
class Mock { | |
public $target; | |
public function __construct($target) { | |
$this->target = $target; | |
} | |
} | |
class Stub { | |
public $refl; | |
public function __construct($target) { | |
$this->refl = new \ReflectionClass($target); | |
$this->obj = $this->refl->newInstanceArgs(array_slice(func_get_args(), 1)); | |
} | |
public function __call($name, $args) { | |
return $this->refl->getMethod($name)->invokeArgs($this->obj, $args); | |
} | |
} | |
class AspectStub extends Stub { | |
public $aspects = array(); | |
public function addAspect(Aspect $aspect) { | |
if ($aspect->getPointcut()->matchesClass($this->refl)) { | |
$this->aspects[] = $aspect; | |
} | |
} | |
public function __call($name, $args) { | |
$method = $this->refl->getMethod($name); | |
foreach ($this->aspects as $aspect) { | |
if ($aspect->getPointcut()->matchesMethod($method)) { | |
$advice = $aspect->getAdvice(); | |
$invocation = new Invocation($this->obj, $method, $args); | |
$advice->before($invocation); | |
$return = $invocation->proceed(); | |
$advice->after($invocation); | |
return $return; | |
} | |
} | |
return $method->invokeArgs($this->obj, $args); | |
} | |
} | |
############################################################################## | |
$w = new AspectStub('Wallet', 0.33); // new Wallet(0.33); | |
$w->addAspect(new WalletAspect()); | |
$w->add(1.66); | |
print($w->getBalance() . PHP_EOL); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment