AOP面向切面编程
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是laravel框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
laravel中间件
介绍与案例来自官方:laravel中间件
laravel中间件提供了一种方便的机制来检查和过滤进入应用程序的 HTTP 请求。例如,Laravel 包含一个中间件,用于验证您的应用程序的用户是否已通过身份验证。如果用户未通过身份验证,中间件会将用户重定向到您的应用程序的登录屏幕。但是,如果用户通过了身份验证,中间件将允许请求进一步进入应用程序。
可以编写额外的中间件来执行除身份验证之外的各种任务。例如,日志中间件可能会记录对您的应用程序的所有传入请求。Laravel框架中包含了几个中间件,包括用于身份验证和 CSRF 保护的中间件。所有这些中间件都位于app/Http/Middleware目录中。
创建中间件命令:
php artisan make:middleware EnsureTokenIsValid
此命令将EnsureTokenIsValid在您的app/Http/Middleware目录中放置一个新类。在这个中间件中,如果提供的token输入匹配指定的值,我们将只允许访问路由。否则,我们会将用户重定向回homeURI:
<?php
namespace App\Http\Middleware;
use Closure;
class EnsureTokenIsValid
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->input('token') !== 'my-secret-token') {
//令牌不匹配,则返回http重定向
return redirect('home');
}
//匹配通过,继续执行
return $next($request);
}
}
业务需求可以在请求之前也可以在请求之后执行,这个取决于 n e x t ( next( next(request)
//写法一,请求前
public function handle($request, Closure $next)
{
// 此处执行请求前的业务需求
return $next($request);
}
//写法二,请求前,也可以请求前后都加入需求
public function handle($request, Closure $next)
{
// 此处执行请求前的业务需求
$response = $next($request);
// 此处执行请求后的业务需求
return $response;
}
理解中间件的实现
下面需要用到闭包
//闭包的2种写法
(function(){echo 1;})(); //最后的()为执行闭包
$a = function(){echo 1;};
$a(); //最后的()为执行闭包
公共代码(用于下方3种实现方式,这里创建了3个中间件类,和一个Controller类):
class middleware1{
public function handle(Closure $next) //约束必须传入闭包
{
echo 'class middleware1 --前<br>';
$next();
echo 'class middleware1 --后<br>';
}
}
class middleware2{
public function handle(Closure $next) //约束必须传入闭包
{
echo 'class middleware2 --前<br>';
$next();
echo 'class middleware2 --后<br>';
}
}
class middleware3{
public function handle(Closure $next) //约束必须传入闭包
{
echo 'class middleware3 --前<br>';
$next();
echo 'class middleware3 --后<br>';
}
}
class Controller{
public function index(){
echo 'this is controller<br>';
}
}
中间件的实现更像一个管道,request通过层层管道,最后再response返回给客户,
官方也是通过Pipeline(管道)类来实现中间件,先看看下图,再感受下下方的实现代码
原生面向过程实现中间件
面向过程,以闭包方式一层层包裹,码了个思想,码了个寂寞,emmm…无法扩展,根本不能用
(function(){
echo 'middleware1 --前<br>';
(function(){
echo 'middleware2 --前<br>';
(function(){
echo 'middleware3 --前<br>';
(function(){
(new Controller)->index(); //这里return结果是个闭包,需要最后再加()执行闭包
})();
echo 'middleware3 -- 后<br>';
})();
echo 'middleware2 -- 后<br>';
})();
echo 'middleware1 -- 后<br>';
})();
运行:
原生面向对象实现中间件
面向对象,类与闭包结合的方式
(new middleware1)->handle(
(function(){
(new middleware2)->handle(
(function(){
(new middleware3)->handle(
(function(){
(new Controller)->index(); //这里return结果是个闭包,需要最后再加()执行闭包
})
);
})
);
})
);
输出:
array_reduce管道式实现中间件
class pipeline{
//中间件注册
private $pipes = [
'middleware1',
'middleware2',
'middleware3',
];
/**
* Get a Closure that represents a slice of the application onion.
*
* @return \Closure
*/
public function carry(){
return function ($stack,$pipe){
return function () use ($stack, $pipe){
return (new $pipe)->handle($stack);
};
};
}
public function then(){
//核心实现:array_reduce() 将回调函数 callback 迭代地作用到 array 数组中的每一个单元中,从而将数组简化为单一的值。
//array_reverse() 接受数组 array 作为输入并返回一个单元为相反顺序的新数组。
//call_user_func 第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数。
call_user_func(array_reduce(array_reverse($this->pipes), $this->carry(),function (){
(new Controller())->index();
}));
}
}
$p = new pipeline();
$p->then();
输出: