不积跬步无以至千里不积小流无以成江海
装饰者模式是在开放-关闭原则下实现动态添加或者减少功能的一种方式,类似于洋葱,分很多层,每一层都有一定的功能,可以随时添加和修改这些层,官方将这些层称之为中间件Middleware。
前置知识
1、mixed array_reduce ( array $array , callable $callback [, mixed $initial = NULL ] )
array_reduce() 将回调函数 callback 迭代地作用到 array 数组中的每一个单元中,从而将数组简化为单一的值
array 输入的 array
mixed callback ( mixed $carry , mixed $item )
carry 携带上次迭代里的值; 如果本次迭代是第一次,那么这个值是 initial。
item 携带了本次迭代的值。
initial 如果指定了可选参数 initial,该参数将在处理开始前使用,或者当处理结束,数组为空时的最后一个结果。
$a = [1, 2, 3, 4, 5];
function sum($carry, $item)
{
$carry += $item;
echo $carry . '<br>'; // 1 3 6 10 15
return $carry;
}
var_dump(array_reduce($a, 'sum')); // int(15)
function product($carry, $item)
{
$carry *= $item;
echo $carry . '<br>'; // 10 20 60 240 1200
return $carry;
}
var_dump(array_reduce($a, 'product',10)); // int(1200)
$x = [];
var_dump(array_reduce($x, "sum", "No data to reduce"));
2、call_user_func
把第一个参数作为回调函数调用 mixed call_user_func ( callable $callback [, mixed $parameter [, mixed $... ]] ) 第一个参数 callback 是被调用的回调函数,其余参数是回调函数的参数
3、装饰者模式
<?php
interface Decorator
{
public function display();
}
class XiaoFang implements Decorator
{
private $name;
public function __construct($name)
{
$this->name = $name;
}
public function display()
{
echo "我是" . $this->name . "我出门了!!!" . '<br>';
}
}
class Finery implements Decorator
{
private $component;
public function __construct(Decorator $compent)
{
$this->component = $compent;
}
public function display()
{
$this->component->display();
}
}
class Shoes extends Finery
{
public function display()
{
echo '穿上鞋子' . '<br>';
parent::display();
}
}
class Skirt extends Finery
{
public function display()
{
echo "穿上裙子" . '<br>';
parent::display();
}
}
class Fire extends Finery
{
public function display()
{
echo '出门前先整理头发' . '<br>';
parent::display();
echo '出门后再整理一下头发' . '<br>';
}
}
$xiaofang = new XiaoFang('小芳');
$shoes = new Shoes($xiaofang);
$skirt = new Skirt($shoes);
$fire = new Fire($skirt);
$fire->display();
/**
* 1、出门前先整理头发
* 2、调用$skirt的diaplay()方法:穿上裙子
* 3、调用$shoes的display()方法:穿上鞋子
* 4、调用$xiaofang的diaplay()方法:我是小芳,我出门了
* 5、出门后再整理一下头发
*/
简化版的中间件启动顺序
<?php
interface Step
{
public static function go(Closure $next);
}
class FirstStep implements Step
{
public static function go(Closure $next)
{
echo "开启session,获取数据" . '<br>';
$next();
echo "保存数据,关闭session" . '<br>';
}
}
function goFun($step, $className)
{
return function () use ($step, $className) {
return $className::go($step);
};
}
function then()
{
$steps = ["FirstStep"];
$prepare = function () {
echo "请求向路由器传递,返回响应" . '<br>';
};
/**
* 第一个参数是要处理的数组
* 第二个参数是处理函数名称或回调函数
* 第三个参数为可选参数,为初始化参数,将被当作数组中的第一个值来处理,如果数组为空则作为返回值
* 这里第三个参数传递一个回调函数,该函数用于将请求向路由器继续传递,返回响应
* 第一个参数为数组,该数组记录了外层功能的类名
* goFun函数作为处理数组的回调函数
* array_reduce()最终返回的是一个回调函数,即$go
* $go = function() {
* return $FirstStep::go(function() {
* echo "请求向路由器传递,返回响应" . '<br>';
* });
* }
*/
$go = array_reduce($steps, "goFun", $prepare);
$go();
}
then();
升级版的中间件依次执行顺序
<?php
interface Middleware
{
public static function handle(Closure $next);
}
class VerifyCsrfToken implements Middleware
{
public static function handle(Closure $next)
{
echo "验证Csrf-Token" . '<br>';
$next();
}
}
class ShareErrorsFromSession implements Middleware
{
public static function handle(Closure $next)
{
echo "如果session中有'error'变量,则共享他" . '<br>';
$next();
}
}
class StartSession implements Middleware
{
public static function handle(Closure $next)
{
echo "开启session" . '<br>';
$next();
echo "保存数据,关闭session" . '<br>';
}
}
class AddQueuedCookieToResponse implements Middleware
{
public static function handle(Closure $next)
{
$next();
echo "添加下一次请求需要的cookie" . '<br>';
}
}
class EncryptCookie implements Middleware
{
public static function handle(Closure $next)
{
echo "对输入请求的cookie进行解密" . '<br>';
$next();
echo "对输出响应的cookie进行加密" . '<br>';
}
}
class CheckFormaintenanceMode implements Middleware
{
public static function handle(Closure $next)
{
echo "确定当前程序是否处于维护状态" . '<br>';
$next();
}
}
function getSlice()
{
return function ($stack, $pipe) {
return function () use ($stack, $pipe) {
return $pipe::handle($stack);
};
};
}
function then()
{
$pipes = [
"CheckFormaintenanceMode",
"EncryptCookie",
"AddQueuedCookieToResponse",
"StartSession",
"ShareErrorsFromSession",
"VerifyCsrfToken"
];
$firstSlice = function () {
echo "请求向路由器传递,返回响应" . "<br>";
};
$pipes = array_reverse($pipes);
call_user_func(
array_reduce($pipes, getSlice(), $firstSlice)
);
}
then();
VerifyCsrfToken::handle(
function () {
echo "请求向路由器传递,返回响应" . "<br>";
}
);
/**************************逻辑分析*****************************
ShareErrorsFromSession::handle(
VerifyCsrfToken::handle(
function () {
echo "请求向路由器传递,返回响应" . "<br>";
}
)
);
StartSession::handle(
ShareErrorsFromSession::handle(
VerifyCsrfToken::handle(
function () {
echo "请求向路由器传递,返回响应" . "<br>";
}
)
)
);
AddQueuedCookieToResponse::handle(
StartSession::handle(
ShareErrorsFromSession::handle(
VerifyCsrfToken::handle(
function () {
echo "请求向路由器传递,返回响应" . "<br>";
}
)
)
)
);
EncryptCookie::handle(
AddQueuedCookieToResponse::handle(
StartSession::handle(
ShareErrorsFromSession::handle(
VerifyCsrfToken::handle(
function () {
echo "请求向路由器传递,返回响应" . "<br>";
}
)
)
)
)
);
CheckFormaintenanceMode::handle( // 确定当前程序是否处于维护状态
EncryptCookie::handle( // 对输入请求的cookie进行解密
AddQueuedCookieToResponse::handle(
StartSession::handle( // 开启session,获取数据
ShareErrorsFromSession::handle( // 如果session中有error变量,则共享他
VerifyCsrfToken::handle( // 验证csrf-token
function () {
echo "请求向路由器传递,返回响应" . "<br>"; // 请求向路由器传递,返回响应
}
)
)
) // 保存数据,关闭session
) // 添加下一次请求需要的cookie
)
// 对输出响应的cookie进行解密
);
* ****************************************************************/