Реализация промежуточного программного обеспечения PHP-фреймворка

задняя часть PHP Laravel

0x00 Предисловие

Промежуточное программное обеспечение — это функция, предоставляемая многими фреймворками PHP, и я был удивлен и взволнован, когда впервые узнал об этом. Поскольку его роль слишком сильна, до того, как не будет промежуточного программного обеспечения, мы должны написать проверку разрешений и некоторые публичные операции в методе контроллера, тогда контроллер станет очень раздутым, что снизит читабельность и ремонтопригодность. Но с промежуточным программным обеспечением мы можем написать эти операции в промежуточном программном обеспечении, а затем, используя различные комбинации промежуточного программного обеспечения, мы можем не только выполнить требования, но и уменьшить связанность кода. Поскольку промежуточное ПО хорошо во всех отношениях, как оно реализовано? чтениеLaravelиSlimВ процессе работы с исходным кодом (мазохистский процесс, который заставляет людей чувствовать себя очень трудоемкими, измученными и чувствовать себя тарелками /(ㄒoㄒ)/~~) я обнаружил, что ключевым моментом является закрытие нескольких промежуточных программ (некоторые фреймворки промежуточных программ не поддерживаются). реализуется через замыкания, но принадлежитcallableКатегория , совместно именуемая замыканиями для удобства написания) черезarray_reduceИли оберните его в процесс закрытия в цикле.

0x01 разминка

Когда дело доходит до промежуточного программного обеспечения, люди часто представляют себе эту картину.

middleware

Выглядит удивительно и пугающе, но если присмотреться, этот процесс на самом деле выглядит как вложенный вызов функции.Middleware2(Middleware1(App()))Шерстяная ткань? Но этот вложенный вызов явно неверен, потому что сначала выполняется PHP.App()вместоMiddleware2Но как насчет вложенных замыканий? Пример кода приведен ниже:

$allMiddleware = function () {
    echo 'start middleware2' . PHP_EOL;
  
    (function () {
        echo 'start middleware1' . PHP_EOL;
        // app
        (function () {
            echo 'app' . PHP_EOL;
        })();
        // end app
        echo 'end middleware1' . PHP_EOL;
    })();
  
    echo 'end middleware2' . PHP_EOL;
};
$allMiddleware();

// 输出
// start middleware2
// start middleware1
// app
// end middleware1
// end middleware2

0x02 мышление

Эй, приведенный выше код работает так, как и ожидалось, но этот код кажется немного руо (чжи). Но на самом деле приведенный выше код$allMiddlewareЭто результат комбинации промежуточного программного обеспечения, поэтому мы коснулись порога Теперь, пожалуйста, подумайте, как автоматически комбинировать следующие замыкания промежуточного программного обеспечения?

// 数据库中间件
$db = function (Closure $next) {
    echo '成功建立数据库连接' . PHP_EOL;
    $next();
    echo '成功关闭数据库连接' . PHP_EOL;
};
// 点赞中间件
$like = function (Closure $next) {
    echo '点赞+1' . PHP_EOL;
    $next();
    echo '点赞+2' . PHP_EOL;
};
// 内容闭包
$app = function () {
    echo '文章内容' . PHP_EOL;
};

больше параметров$nextкакого черта?$nextЭто следует понимать как «закрытие, упакованное всеми функциями закрытия промежуточного программного обеспечения после этого промежуточного программного обеспечения», просто используйтеMiddleware2С точки зрения его$nextэтоMiddleware1иAPPУпакованная крышка (см. два самых внутренних слоя на рисунке выше).

0x03 ответы

Код ответа следующий:

// array_reduce 实现
$allMiddleware = [$like, $db];
$go = array_reduce($allMiddleware, function ($next, $middleware) {
    return function () use ($next, $middleware) {
        $middleware($next);
    };
}, $app);
$go();

// foreach 实现
$allMiddleware = [$like, $db];
$next = $app;
foreach ($allMiddleware as $middleware) {
    $next = function () use ($next, $middleware) {
        return $middleware($next);
    };
}
$next();

Две реализации, но тот же принцип, так что только объяснитеforeachреализация версии. Первый — сформировать массив всего промежуточного ПО и поместить$nextУстановить как$app, а затем запустить цикл$nextиmiddlewareсформировать новое замыкание и присвоить$next,так$nextОн будет продолжать объединять предыдущие замыкания и, наконец, станет одним из них. Затем, выполнив окончательный$nextчтобы получить результат. Конечно, мне может быть нелегко понять то, что я сказал пустыми словами. Лучший способ - запустить этот код в моем мозгу. ㄒ)/~~) и тогда вы сможете понять. Тоже не ясноarray_reduceфункция можеткликните сюда.

0x04 лучшая версия

Чтобы лучше понять предыдущее промежуточное ПО, достаточно$nextпараметры, но промежуточное ПО фактического фреймворка будет иметь аналогичные$requestпараметры и поддерживает возвращаемые значения$response(например, Laravel), ниже приведен код реализации промежуточного программного обеспечения, похожего на Laravel (просто имитация, как у тигров и кошек). Одна уловка, все уловки, это блюдо не объяснит этого (если это затронет мои слепые пятна знаний, это будет ГГ, О(∩_∩)О, ха-ха~).

$db = function ($request, Closure $next) {
    echo '成功建立数据库连接' . PHP_EOL;
    $response = $next($request);
    echo '成功关闭数据库连接' . PHP_EOL;

    return $response;
};

$like = function ($request, Closure $next) {
    echo '点赞+1' . PHP_EOL;
    $response = $next($request);
    echo '点赞+2' . PHP_EOL;

    return $response;
};

$app = function ($request) {
    echo $request . PHP_EOL;
    return '一个无聊的返回值';
};

$allMiddleware = [$like, $db];
$next = $app;
foreach ($allMiddleware as $middleware) {
    $next = function ($request) use ($middleware, $next) {
        return $middleware($request, $next);
    };
}

$response = $next('O(∩_∩)O');
echo $response;

0x05 Сводка

(⊙v⊙) Что ж, совсем немного контента достаточно, чтобы я почувствовал удовлетворение O(∩_∩)О, ха-ха~. Кроме того, если в статье есть ошибка, надеюсь, все смогут указать на нее, а если возникнут вопросы, то можно обсудить друг с другом :-D.

мой блог оригинал