美文网首页
laravel Pipeline 原理的详细解析

laravel Pipeline 原理的详细解析

作者: sorry510 | 来源:发表于2022-03-09 16:41 被阅读0次

    laravel 中间件使用了 Pipeline

    • vendor\laravel\framework\src\Illuminate\Foundation\Http\Kernel.php
     return (new Pipeline($this->app))
          ->send($request)
          ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
          ->then($this->dispatchToRouter());
    
    • then 函数
    public function then(Closure $destination)
    {
        $pipeline = array_reduce(
                array_reverse($this->pipes), $this->carry(), $this->prepareDestination($destination)
            );
    
        return $pipeline($this->passable);
    }
    
    • carry 函数
    protected function carry()
    {
        return function ($stack, $pipe) {
            return function ($passable) use ($stack, $pipe) {
                if (is_callable($pipe)) {
                    return $pipe($passable, $stack);
                } elseif (! is_object($pipe)) {
                    list($name, $parameters) = $this->parsePipeString($pipe);
                    $pipe = $this->getContainer()->make($name);
                    $parameters = array_merge([$passable, $stack], $parameters);
                } else {
                    $parameters = [$passable, $stack];
                }
                return method_exists($pipe, $this->method)
                                ? $pipe->{$this->method}(...$parameters)
                                : $pipe(...$parameters);
            };
        };
    }
    

    让我们去掉分支条件,创建一个简单例子

    定义管道执行函数

    function reducePipe($pipesFn, $initFn) {
        return array_reduce($pipesFn, function($carry, $pipe) {
            return function($data) use($carry, $pipe) {
                return $pipe($data, $carry);
            };
        }, $initFn);
    }
    

    定义3个管道函数 $pipes

    $pipes = [];
    foreach(range(1, 3) as $row) {
        $pipes[] = function($data, $next) use($row) {
            echo 'pipe-before' . $row . PHP_EOL;
            $data->num += $row;
            $data = $next($data);
            echo 'pipe-hehind' . $row . PHP_EOL;
            return $data;
        };
    }
    

    定义初始化函数 $init

    $init = function($data) {
        echo 'init start' . PHP_EOL;
        var_dump($data);
        echo 'init end' . PHP_EOL;
        return 'init';
    };
    

    定义初始化数据 $data

    $data = new StdClass;
    $data->num = 1;
    

    执行函数

    $reduce = reducePipe($pipes, $init); // 获取 array_reduce 后的函数
    $result = $reduce($data);
    var_dump($result); // 结果和每个$pipe的 return 有关,传递关系 init -> h1 -> h2 -> h3
    
    • 执行结果
    pipe-before3
    pipe-before2
    pipe-before1
    init start
    object(stdClass)#5 (1) {
      ["num"]=>
      int(7)
    }
    init end
    pipe-hehind1
    pipe-hehind2
    pipe-hehind3
    string(4) "init"
    

    ps: 所以为了得到正确的执行顺序,需要 array_reverse($pipes) 翻转数组

    解析 array_reduce 的执行过程

    洋葱模型 before3->before2->before1->init->behind1->hehind2->hebind3

    • $reduce
    function($data) use($carry, $pipe) {
          return $pipe($data, $carry);
    };
    
    • $pipe
     function($data, $next) use($row) {
            echo 'pipe-before' . $row . PHP_EOL;
            $data->num += $row;
            $data = $next($data);
            echo 'pipe-hehind' . $row . PHP_EOL;
            return $data;
      };
    

    reduce1

    $reduce1 = function($data) {
        $row = 1;
        echo 'pipe-before' . $row . PHP_EOL;
        $data->num += $row;
    
        // $next($data) $next == $init
        echo 'init start' . PHP_EOL;
        var_dump($data);
        echo 'init end' . PHP_EOL;
        $data = 'init';
    
        echo 'pipe-hehind' . $row . PHP_EOL;
        return $data;
    };
    

    reduce2

    $reduce2 = function($data) use($reduce1) {
        $row = 2;
        echo 'pipe-before' . $row . PHP_EOL;
        $data->num += $row;
    
        // $next($data) $next == $reduce1
        $data = $reduce1($data);
    
        echo 'pipe-hehind' . $row . PHP_EOL;
        return $data;
    };
    

    reduce3

    $reduce3 = function($data) use($reduce2) {
        $row = 3;
        echo 'pipe-before' . $row . PHP_EOL;
        $data->num += $row;
    
        // $next($data) $next == $reduce2
        $data = $reduce2($data);
    
        echo 'pipe-hehind' . $row . PHP_EOL;
        return $data;
    };
    

    执行 reduce3

    var_dump($reduce3($data));
    

    执行结果

    与之前的相同

    pipe-before3
    pipe-before2
    pipe-before1
    init start
    object(stdClass)#5 (1) {
      ["num"]=>
      int(7)
    }
    init end
    pipe-hehind1
    pipe-hehind2
    pipe-hehind3
    string(4) "init"
    

    相关文章

      网友评论

          本文标题:laravel Pipeline 原理的详细解析

          本文链接:https://www.haomeiwen.com/subject/qcmtdrtx.html