請求處理管道個人理解

twisted-fate發表於2017-08-27

學前必備知識點:閉包(Closure),array_reduce(),array_reverse()
可選進階知識點:裝飾者模式

簡易模擬請求處理管道

<?php

/**
 * Interface Step
 */
interface Step {
    /**
     * @param Closure $next
     * @return mixed
     */
    public static function go(Closure $next);
}

/**
 * 中介軟體1
 * Class FirstStep
 */
class FirstStep implements Step {
    /**
     * @param Closure $next
     */
    public static function go (Closure $next)
    {
        echo "開啟session,獲取資料...".'<br>';
        $next();
        echo "儲存資料,關閉SESSION...".'<br>';
    }
}

/**
 * 中介軟體2
 * Class SecondStep
 */
class SecondStep implements Step {
    /**
     * @param Closure $next
     */
    public static function go(Closure $next)
    {
        echo "檢測使用者許可權";
        $next();
    }
}

/**
 * array_reduce自定義函式
 * @param $step
 * @param $className
 * @return Closure
 */
function goFun($step, $className)
{
    return function() use($step,$className)
    {
        return $className::go($step);
    };
}

/**
 * 模擬執行處理管道
 */
function then()
{
    $steps = ["FirstStep","SecondStep"];
    $prepare = function() { echo "請求向路由器傳遞,返回響應...".'<br>';};
    $go = array_reduce($steps,"goFun",$prepare);
    //這裡是關鍵,第一個是要處理的陣列,第二個是自定義回撥函式,
    //第三個是可選引數,為初始化引數,被當作array_reduce中第一個值來處理,若陣列為空則作為返回值。
    //var_dump($go);
    //$test = new Reflection($go);
    $go();
}

then();

/* 
 * 詳細解析
 * 定義步驟一,步驟二
 * 定義初始化引數$preapres
 * array_reduce執行過程:
 * 1.生成閉包函式function()
    {
        FirstStep::go($prepares);
    };
 * 2.生成function()
    {
        SecondStep::go(function()
             {
                FirstStep::go($prepares);
             };);
    };
 * 最終執行順序是每個類中的go方法:SecondStep,First的第一個步驟,$prepares,First的第二個步驟,可以看到與陣列['FirstStep,'SecondStep']的順序反過來了
 * 在實際Laravel的管道中用了array_reverse,使得執行順序與陣列定義的順序一致
 * 這裡看起來有點類似遞迴,先一層一層進入,再把執行權一層一層轉回去
在閉包中傳入閉包…..
執行閉包 , 在閉包的語句裡再執行傳入的閉包
 * */

laravel中的請求處理管道

<?php
interface Middleware
{
    public static function handle(Closure $next);
}

class VerifyCsrfToken implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "驗證csrf-token.......";
        $next();
    }
}

class ShareErrorsFromSession implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "如果session中有errors變數,共享他....";
        $next();
    }
}

class StartSession implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "開啟session,獲取資料....";
        $next();
        echo "儲存資料,關閉session..";

    }
}

class AddQueuedCookiesToResponse implements Middleware
{
    public static function handle(Closure $next)
    {
        $next();
        echo "新增下一次請求需要的cookie...";
    }
}

class EncryptCookies implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "對輸入請求的cookie進行解密...";
        $next();
        echo "對輸出響應的cookie進行加密...";
    }
}

class CheckForMaintenanceMode implements Middleware
{
    public static function handle(Closure $next)
    {
        echo "確定當前程式是否處於維護狀態...";
        $next();
    }
}

function getSlice()
{
    return function ($stack, $pipe) {
        return function () use ($stack, $pipe) {
            return $pipe::handle($stack);
        };
    };
}

function then()
{
    $pipes= [
        "CheckForMaintenanceMode",
        "EncryptCookies",
        "AddQueuedCookiesToResponse",
        "StartSession",
        "ShareErrorsFromSession",
        "VerifyCsrfToken"
    ];
    $firstSlice = function () {
        echo "請求向路由器傳遞,返回響應....";
    };
    $pipes = array_reverse($pipes);
    call_user_func(
        array_reduce($pipes, getSlice(), $firstSlice)
    );
}

then();

/*
 * 先reverse把陣列倒轉過來
 * 於是先生成VerifyCsrfTokenLLhanle($firstSlice);
 * 再生成ShareErrorsFromSession::handle($上一步生成的閉包);
 * ......
 * ....
 * 最後生成CheckForMaintenanceMode::handle($上一步生成的閉包);
 *
 * 於是執行順序就變為腦圖
 *
 */

執行順序腦圖

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章