PHP一个类AOP的实现

由于项目有一个需求,需要在原来的代码上做一个封装. 由于不想修改原有代码, 查了一下, PHP没有方便的支持AOP的方法,于是参考了网上一些文章,写了个包装器, 可以在不修改原有代码的基础上为函数添加before和after实现.

标签: <无>

代码片段(3)[全屏查看所有代码]

1. [代码]核心类

01<?php
02
03/**
04* 包装器(Wrapper).
05* Wrapper是一个AOP_LIKE的实现. 也可以看作监听者模式的实现.
06* 一个Wrapper报装了一个对象(source). source可以是任意对象(不包括数组及原子类型),甚至是一个Wrapper.
07*
08* 包装器可以任意添加饰品(Decoration).通过Wrapper调用source的函数的流程将是:
09* unpacking --> teardown --> open --> setup --> packing.
10*
11* 例如调用source->doXX(),各个流程将是:
12* unpacking: 解包. 这是调用任意source的函数都会调用的方法;
13* teardown: 撕掉饰品. 对于Wrapper中的每个Decoration,调用其before()函数;
14* open: 真正调用source->doXX()函数;
15* setup: 重新贴上饰品. 对于Wrapper中的每个Decoration,调用其after()函数;
16* packing: 重新打包. 这是调用任意source的函数都会调用的方法;
17*
18*/
19classWrapper{
20private$source;
21
22/**
23* @var bool
24*/
25private$undecorated;
26
27/**
28* @var array[Decoration]
29*/
30private$decorations=array();
31
32publicfunction__construct($source){
33$this->source =$source;
34}
35
36publicfunction__call($name,$parameters){
37$this->unpacking($name,$parameters);
38$this->tearDown($name,$parameters);
39
40// opening
41if(method_exists($this->source,$name)){
42$retval= call_user_func_array(array($this->source,$name),$parameters);
43}
44
45$this->setup($retval,$name,$parameters);
46$this->packing($retval,$name,$parameters);
47
48return$retval;
49}
50
51publicfunctionunpacking($name,$parameters){
52}
53
54publicfunctionpacking($name,$parameters){
55}
56
57publicfunctiontearDown($name,$parameters){
58if($this->undecorated){
59return;
60}
61foreach($this->decorationsas$d){
62$d->before($name,$parameters);
63}
64}
65
66publicfunctionsetup($retval,$name,$parameters){
67if($this->undecorated){
68return;
69}
70foreach($this->decorationsas$d){
71$d->after($retval,$name,$parameters);
72}
73}
74
75publicfunctiondecarate($decoration){
76$this->decorations[] =$decoration;
77}
78
79
80
81publicstaticfunctionwrap($source){
82// wrap the source
83$wrapperConfig= app()->wrappers[get_class($source)];
84if($wrapperConfig){
85$wrapperClass=$wrapperConfig['class'];
86$wrapper=new$wrapperClass($source);
87
88foreach($wrapperConfig['decorations']as$item){
89$decoration=new$item;
90$wrapper->decarate($decoration);
91}
92}
93return$wrapper?$wrapper:$source;
94}
95
96}
97
98?>

2. [代码]配置

01'wrappers'=>array(
02'ContentService'=>array(
03'class'=>'ContentWrapper',
04'decorations'=>array(
05'DasaiContentDecoration',
06)
07),
08'AOPWorker'=>array(//for test
09'class'=>'DiagnosisWrapper',
10'decorations'=>array(
11'DasaiDiagnosisDecoration'
12),
13),
14),

3. [代码]测试代码

01classAOPWorker{
02publicfunctiontestAOP(){
03Debugger::print_r(
04"\n工人:我要做一大堆操作了
05\n工人:... ...
06\n工人:好了 做完了\n");
07return'OK';
08}
09
10}
11
12
13publicfunctiontestAOP(){// test aop 测试入口
14$aop= Wrapper::wrap(newAOPWorker());
15$aop->testAOP(33347);
16}
17
18
19
20classDiagnosisWrapperextendsWrapper{
21
22publicfunctionunpacking($name,$parameters){
23echo"\nDiagnosisWrapper:喂,有人调用$name,我要解包了.\n";
24}
25
26
27publicfunctionpacking($retval,$name,$parameters){
28echo"\nDiagnosisWrapper:喂,调用$name,结果为$retval,重新打包好了.\n";
29}
30}
31
32
33
34classDasaiDiagnosisDecorationextendsDecoration {
35publicfunctionbefore($name,$parameters){
36echo"\r\nDasaiDiagnosisDecoration:开始调用$name,已经告诉张三李四了.\n";
37}
38
39publicfunctionafter($retval,$name,$parameters){
40echo"\nDasaiDiagnosisDecoration:结束调用$name,告诉霍金和Sheldon了.\n";
41}
42}