未分类

PHP 中间件的简单实现

定义四个中间件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$app = function () {
echo 'app';
};

$m1 = function () {
echo "m1\n";
};

$m2 = function () {
echo "m2\n";
};

$m3 = function () {
echo "m3\n";
};

其中 app 表示最后要执行的业务逻辑。现在只是定义了四个中间件,但是这些中间件之间没有先后顺序,修改一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

$app = function () {
echo 'app';
};

$m1 = function () use ($app) {
echo "m1\n";
$app();
};

$m2 = function () use ($m1) {
echo "m2\n";
$m1();
};

$m3 = function () use ($m2) {
echo "m3\n";
$m2();
};

$m3();

修改之后,每一个中间件都使用闭包手动绑定了下一个要执行的中间件。当调用 $m3() 时,中间件按照 m3m2m1app 的顺序依次执行。

再修改一下,下一个中间件我们当做参数传进去,在中间件内部调用 $next() 执行下一个中间件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php

$app = function () {
echo 'app';
};
$next = function () use ($app) {
return $app();
};

$m1 = function ($next) {
echo "m1\n";
$next();
};
$next = function () use ($m1, $next) {
return $m1($next); // 绑定 m1 中间件与下一个中间件
};

$m2 = function ($next) {
echo "m2\n";
$next();
};
$next = function () use ($m2, $next) {
return $m2($next); // 绑定 m2 中间件与下一个中间件
};

$m3 = function ($next) {
echo "m3\n";
$next();
};
$next = function () use ($m3, $next) {
return $m3($next); // 绑定 m3 中间件与下一个中间件
};

$next();

再修改一下,这次先将中间件放入栈中,绑定的操作放到最后再做,同时传入 $request$response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php

$middlewares = [];

$app = function ($request, $response) {
echo 'app';
};
array_push($middlewares, $app);

$m1 = function ($request, $response, $next) {
echo "m1\n";
$next();
};
array_push($middlewares, $m1);

$m2 = function ($request, $response, $next) {
echo "m2\n";
$next();
};
array_push($middlewares, $m2);

$m3 = function ($request, $response, $next) {
echo "m3\n";
$next();
};
array_push($middlewares, $m3);

$next = null;
$request = new Request();
$response = new Response();
foreach ($middlewares as $middleware) {
$next = function () use ($middleware, $next) {
return call_user_func_array($middleware, [$request, $response, $next]);
};
}

$response = $next();
send($response);

中间件的执行顺序是后进的先执行,但是绑定的时候是要从先进的开始绑定。