唐磊的个人博客

PHP中的AOP

已经从腾讯离职了,今天在学校整理电脑里面的资料,看到了以前写的一篇文章,发到KM里面了,虽然没啥响应的人。我这里还是在blog里记录下(原文含有保密信息,稍稍改下),给备份一下。下面说说背景:

网站的服务质量很重要,大型网站为了保证其服务质量,会采取很多措施。比如自动化测试监控等。之前在项目中就负责将一些接口调用状态信息等上报一个统一管理的平台。比如,A接口里面,去调用了B接口,这个B接口有可能是自己项目当中的接口,也有可能是其他项目当中的接口(例如朋友网调用QQ空间的接口),在调用B接口后,有可能返回失败,这样就得把这个失败信息log下来,上报。方便出问题时定位准确。

在以前的做法中,这个模块间调用的上报分为如下几个方法:

  • tick():调用接口开始,记录调用时间;
  • 接口调用();
  • report():这里就是根据上一步中的结果,确定是到底上报成功,还是失败,或者是超时(只是记录调用完成后的时间,超时等由统一管理的平台配置)
    后来想想,A这个接口去调用B这个接口,却将tick,report这样的方法写在了A里面,然后这些方法跟A这个具体的业务逻辑是没有关系的,代码紧紧耦合在一起,为了解耦和,联想到以前学java时的AOP,于是就搜索了下php中的,后来搜索到php能通过魔术方法实现aop。下面给出我的实现

具体的业务逻辑类:

class Biz{
function add($param){
echo 'add'.$param ."\t";
return 0;
}
function del($id){
echo 'del' . $id . "\t";
return false;
}
function getInfo($param){
echo 'getInfo' . $param . "\t";
return "getinfo";
}
}

然后在外面封装一层,将业务逻辑的代码包装起来:

//业务逻辑类的包装类
class AOP
{
private $instance;
public function __construct($instance)
{
$this->instance = $instance;
}
public function __call($method, $argument)
{
if(! method_exists($this->instance, $method))
{
throw new Exception('未定义的方法:' . $method);
}
//模拟tick方法
echo 'tick_' . $method . '_'.time(). "\r\n";
//调用具体的业务逻辑
$callBack = array($this->instance, $method);
$return = call_user_func_array($callBack, $argument);
//根据实际情况 上报成功或者失败
if($return === false)
{
echo 'report fail' . "\r\n";
}else {
echo 'report success' . "\r\n";
}
return $return;
}
}

最后有一个统一的工厂去管理所有的业务逻辑代码;现在代码是这样写的,可以考虑单例之类

//工厂方法
class BizFactory
{
public function getBizInstance()
{
return new AOP(new Biz());
}
}

然后去调用相关的业务逻辑时,通过这个统一的工厂去调用;

function doit(){
//不同的业务的话也可以利用抽象工厂等设计模式
$obj = BizFactory::getBizInstance();
//通过类方法去调用
$obj->add(1);
$obj->del(99);
$obj->getInfo(1);
}

执行一下doit();就有如下的结果;

aop,php

这样,是业务逻辑和监控上报状态就隔离出来了,实现了代码的解耦和。

tanglei wechat
欢迎扫描二维码关注我的微信公众号