php管道模式手測

一直在用Laravel框架,很喜歡laravel框架的中間件。在請求到結果以前,若是咱們想要對路由或請求進行額外的處理,簡單的加個Midleware中間件就好了,很簡單,很方即是不是。
最近幾天看了下它的中間件的實現方式,把本身的心得感悟寫下來分享給你們。laravel

瞭解管道模式

laravel的中間件用的是管道模式,咱們先知道管道模式是什麼:設計模式

所謂管道(Pipeline)設計模式就是將會數據傳遞到一個任務序列中,管道扮演者流水線的角色,數據在這裏被處理而後傳遞到下一個步驟

管道,顧名思義,就是一個長長的流水管道,只不過加了許多閥門。因此管道模式大體須要三個角色:管道,閥門和載荷(流水)。以下圖:
圖片描述閉包

管道模式UML模型圖

開始代碼以前,咱們必須先了解管道模式的模型圖
圖片描述框架

簡單的實現

根據上面的模型圖,咱們來實現本身所理解的管道模式的代碼:函數

/**
 * PipelineBuilder 接口 即管道
 * @method pipe 存入多個閥門
 * @method process 輸出
 */
interface PipelineBuilderInterface
{
    public function __construct($payload);
    public function pipe(StageBuilderInterface $stage);
    public function process();
}
// 具體的管道類
class Pipeline implements PipelineBuilderInterface
{
    protected $payload;
    protected $pipes = [];
    public function __construct($payload)
    {
        $this->payload = $payload;
    }

    public function pipe(StageBuilderInterface $stage)
    {
        $this->pipes[] = $stage;

        return $this;
    }

    public function process()
    {
        foreach ($this->pipes as $pipe) {
            call_user_func([$pipe, 'handle'], $this->payload);
        }
    }
}
// 閥門接口
interface StageBuilderInterface
{
    public function handle($payload);
}
// 具體的閥門類
class StageOneBuilder implements StageBuilderInterface
{
    public function handle($payload)
    {
        echo $payload .' 真是個';
    }
}
// 具體的閥門類
class StageTwoBuilder implements StageBuilderInterface
{
    public function handle($payload)
    {
        echo '帥氣的男人';
    }
}
// 輸出:我真是個帥氣的男人
$pipeline = new Pipeline('我');
$pipeline->pipe(new StageOneBuilder)
    ->pipe(new StageTwoBuilder)
    ->process();

底層源碼

先來看看它的底層源碼:ui

return (new Pipeline($this->container))
            ->send($request)
            ->through($middleware)
            ->then(function ($request) use ($route) {
                return $this->prepareResponse(
                    $request, $route->run()
                );
            });

上面的代碼是處理request請求的一部分代碼,send()獲取待處理的數據,through()獲取中間件,then()傳遞閉包函數。
基本上,使用laravel pipelines你能夠將一個實例對象(object)在多個類之間傳遞,就像流水順着管道依次流淌通常,最終呢,層層傳遞,你就獲得了從頭到尾一系列執行操做的「最終」結果。this

模仿laravel pipeline

interface PipelineInterface
{
    public function send($traveler);
    public function through($stops);
    public function via($method);
    public function process();
}

interface StageInterface
{
    public function handle($payload);
}

class StageOne implements StageInterface
{
    public function handle($payload) 
    {
        echo $payload . ' am really an ';
    }
} 

class StageTwo implements StageInterface
{
    public function handle($payload) {
        echo 'awesome man';
    }
} 

class Pipe implements PipelineInterface
{
    protected $container;
    protected $passable;
    protected $pipes = [];
    protected $via = 'handle';

    public function __construct($container)
    {
        $this->container = $container;
    }

    public function send($passable)
    {
        $this->passable = $passable;

        return $this;
    }

    public function through($pipes)
    {
        $this->pipes = is_array($pipes) ? $pipes : func_get_args();

        return $this;
    }

    public function via($method)
    {
        $this->via = $method;

        return $this;
    }

    public function process()
    {
        foreach ($this->pipes as $pipe) {
            call_user_func([$pipe, $this->via], $this->passable);
        }
    }
}
$container = 'a';
$payload = 'wa';
$pipe = new Pipe($container);

// 輸出:I am really an awesome man
$pipe->send($payload)->through([(new StageOne), (new StageTwo)])->process();

結語

上面的代碼並無達到laravel中間件的真正執行部分,例子中只是用到了管道模式的一部分。像then()方法中還用了array_reducearray_reverse函數來處理請求,這一部分有時間會進一步研究。spa

相關文章
相關標籤/搜索