面向切面编程(AOP),也可以成为契约编程。好处和作用有很多。比如降低模块之间的耦合度,进行代码擦除减少重复代码。
在工作过程中,因为要对一部分方法,进行日志环绕处理。如果用代理模式的话,显得过于臃肿。所以,想到了 Java 的 AOP。由于没有找到合适的包,所以自己就手撸了一个。由于比较简单,所以也懒得打包了,目前只实现了简单的函数代理。(流程图如下)
AOP实现类
<?php
namespace App\Http\Intercept\Proxy;
use App\Http\Intercept\Interceptor;
use App\Http\Intercept\InvokeEnhance\Invocation;
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2021/10/8
* Time: 15:14
*/
class ProxyBean
{
private $target = null; //被代理类
private $args = null;// 被代理的构造参数
private $interceptor = null; //代理类
private $ex;
/**
* @param $target //被代理类
* @param $args //被代理的构造参数
* @param Interceptor $interceptor //代理类
* @return ProxyBean
*/
public static function getProxyBean($target,$args,Interceptor $interceptor){
$proxyBean = new ProxyBean();
//被代理的类
$proxyBean->target = $target; //被代理类
$proxyBean->args = $args; //被代理的构造参数
$proxyBean->interceptor = $interceptor; //代理类
return $proxyBean;
}
/**
* 魔术方法 - 调用不存在的方法是,触发代理实现
* @param $name
* @param $arguments
*/
public function __call($name,$arguments) {
return $this->invoke($this->target,$this->args,$name,$arguments);
}
/**
*代理执行
* @param $target //被代理类
* @param $args //被代理类构造参数
* @param $name //被代理类执行方法
* @param $arguments //被代理类执行方法-参数
* @return void|null
*/
public function invoke($target,$args,$name,$arguments){
$exceptionFlag = false;
$retObj = null;
$invocation = new Invocation($target,$args,$name,$arguments);
try {
if ($this->interceptor->before() && $this->interceptor->useAround()){
$retObj = $this->interceptor->around($invocation);
}else{
$retObj = $invocation->proceed();
}
}catch (\Exception $ex){
$exceptionFlag = true;
$this->ex =$ex;
}
$this->interceptor->after();
if ($exceptionFlag){
$this->interceptor->afterThrowing($ex);
}else{
$this->interceptor->afterReturning();
return $retObj;
}
return null;
}
}
契约接口
<?php
namespace App\Http\Intercept;
use App\Http\Intercept\InvokeEnhance\Invocation;
/**
* AOP 约定接口标准
* Created by PhpStorm.
* User: Administrator
* Date: 2021/10/8
* Time: 14:56
*/
interface Interceptor
{
//执行前
public function before() :bool;
//执行后
public function after();
//环绕
public function around(Invocation $invocation);
//运行后执行
public function afterReturning();
//捕获运行错误
public function afterThrowing(\Exception $ex);
//是否启用环绕
public function useAround() :bool;
}
契约自定义
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2021/10/8
* Time: 15:29
*/
namespace App\Http\Intercept;
use App\Http\Intercept\InvokeEnhance\Invocation;
class DatabaseWmsLogInterceptor implements Interceptor
{
public function before(): bool
{
var_dump('before......<br>');
return true;
}
public function after()
{
// TODO: Implement after() method.
}
public function afterReturning()
{
var_dump('afterReturning...<br>');
}
public function afterThrowing(\Exception $ex)
{
var_dump('afterThrowing...'.$ex->getMessage());
}
public function useAround(): bool
{
return true;
}
public function around(Invocation $invocation)
{
echo '<br>================around before...==================<br>';
var_dump('around before...<br>');
var_dump($invocation->getMethodargs());
echo '<br>=================around before...=================<br>';
$obj = $invocation->proceed();
echo '<br>================around after...==================<br>';
var_dump('<br>around after...<br>');
var_dump($obj);
echo '<br>================around after...==================<br>';
return $obj;
}
}
被代理
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2021/10/8
* Time: 15:26
*/
namespace App\Services\Test;
use App\Services\Test\InInterface\HelloService;
class HelloServiceImpl implements HelloService
{
public function sayHello($name)
{
if (empty($name)){
throw new \RuntimeException("parameter is null");
}
var_dump('hello:'.$name);
}
public function sayGoodBy($name,array $arr)
{
var_dump($name.':sayGoodBy:'.json_encode($arr));
return $arr;
}
public static function good($name){
var_dump($name);
return $name;
}
}
实例
/**
* aop 约定式编程
*
* @param int $id
* @return \Illuminate\View\View
*/
public function testDatabaseWmsLogInterceptor()
{
$proxy = ProxyBean::getProxyBean(HelloServiceImpl::class,[],app(DatabaseWmsLogInterceptor::class));
//$proxy->sayHello();
echo '<br>';
$result = $proxy->sayGoodBy('小狗',['one','two']);
var_dump($result);
//return view('testDemo');
}