PHP一个类AOP的实现
由于项目有一个需求,需要在原来的代码上做一个封装. 由于不想修改原有代码, 查了一下, PHP没有方便的支持AOP的方法,于是参考了网上一些文章,写了个包装器, 可以在不修改原有代码的基
由于项目有一个需求,需要在原来的代码上做一个封装. 由于不想修改原有代码, 查了一下, PHP没有方便的支持AOP的方法,于是参考了网上一些文章,写了个包装器, 可以在不修改原有代码的基础上为函数添加before和after实现.
<?php
/**
* 包装器(Wrapper).
* Wrapper是一个AOP_LIKE的实现. 也可以看作监听者模式的实现.
* 一个Wrapper报装了一个对象(source). source可以是任意对象(不包括数组及原子类型),甚至是一个Wrapper.
*
* 包装器可以任意添加饰品(Decoration).通过Wrapper调用source的函数的流程将是:
* unpacking --> teardown --> open --> setup --> packing.
*
* 例如调用source->doXX(),各个流程将是:
* unpacking: 解包. 这是调用任意source的函数都会调用的方法;
* teardown: 撕掉饰品. 对于Wrapper中的每个Decoration,调用其before()函数;
* open: 真正调用source->doXX()函数;
* setup: 重新贴上饰品. 对于Wrapper中的每个Decoration,调用其after()函数;
* packing: 重新打包. 这是调用任意source的函数都会调用的方法;
*
*/
class Wrapper{
private $source;
/**
* @var bool
*/
private $undecorated;
/**
* @var array[Decoration]
*/
private $decorations=array();
public function __construct($source){
$this->source = $source;
}
public function __call($name,$parameters){
$this->unpacking($name,$parameters);
$this->tearDown($name,$parameters);
// opening
if(method_exists($this->source, $name)){
$retval = call_user_func_array(array($this->source,$name),$parameters);
}
$this->setup($retval,$name,$parameters);
$this->packing($retval,$name,$parameters);
return $retval;
}
public function unpacking($name,$parameters){
}
public function packing($name,$parameters){
}
public function tearDown($name,$parameters){
if($this->undecorated){
return;
}
foreach ($this->decorations as $d){
$d->before($name,$parameters);
}
}
public function setup($retval,$name,$parameters){
if($this->undecorated){
return ;
}
foreach ($this->decorations as $d){
$d->after($retval,$name,$parameters);
}
}
public function decarate($decoration){
$this->decorations[] = $decoration;
}
public static function wrap($source){
// wrap the source
$wrapperConfig = app()->wrappers[get_class($source)];
if($wrapperConfig){
$wrapperClass = $wrapperConfig['class'];
$wrapper = new $wrapperClass($source);
foreach ($wrapperConfig['decorations'] as $item){
$decoration = new $item;
$wrapper->decarate($decoration);
}
}
return $wrapper?$wrapper:$source;
}
}
?>
2. [代码]配置 跳至 [1] [2] [3] [全屏预览]
'wrappers'=>array( 'ContentService'=>array( 'class'=>'ContentWrapper', 'decorations'=>array( 'DasaiContentDecoration', ) ), 'AOPWorker'=>array(//for test 'class'=>'DiagnosisWrapper', 'decorations'=>array( 'DasaiDiagnosisDecoration' ), ), ),
3. [代码]测试代码 跳至 [1] [2] [3] [全屏预览]
class AOPWorker{
public function testAOP(){
Debugger::print_r(
"\n工人:我要做一大堆操作了
\n工人:... ...
\n工人:好了 做完了\n");
return 'OK';
}
}
public function testAOP(){// test aop 测试入口
$aop = Wrapper::wrap(new AOPWorker());
$aop->testAOP(33347);
}
class DiagnosisWrapper extends Wrapper{
public function unpacking($name, $parameters){
echo "\nDiagnosisWrapper:喂,有人调用$name,我要解包了.\n";
}
public function packing($retval,$name, $parameters){
echo "\nDiagnosisWrapper:喂,调用$name,结果为$retval,重新打包好了.\n";
}
}
class DasaiDiagnosisDecoration extends Decoration {
public function before($name,$parameters){
echo "\r\nDasaiDiagnosisDecoration:开始调用$name,已经告诉张三李四了.\n";
}
public function after($retval,$name,$parameters){
echo "\nDasaiDiagnosisDecoration:结束调用$name,告诉霍金和Sheldon了.\n";
}
}
- 上一篇:无限级菜单父节点查询所有子节点
- 下一篇:插入数组但不影响原来排序 - PHP
精彩图集
精彩文章






