Laravel 路由管道源码分析

前言 只为学习

Illuminate\Routing\Pipeline 分析

1. 引入

use Closure;//php匿名函数类
use Exception;//php异常类
use Throwable;//php错误处理类
use Illuminate\Http\Request;//框架请求类
use Illuminate\Contracts\Debug\ExceptionHandler;//框架异常处理接口
use Illuminate\Pipeline\Pipeline as BasePipeline;//框架管道核心类
use Symfony\Component\Debug\Exception\FatalThrowableError;//Symfony错误处理类

2. 继承BasePipeline

class Pipeline extends BasePipeline //继承BasePipeline

3. 重载父类prepareDestination

 protected function prepareDestination(Closure $destination)
    {
        return function ($passable) use ($destination) {
            try {
                return $destination($passable);
            } catch (Exception $e) {
                return $this->handleException($passable, $e);//抛出异常
            } catch (Throwable $e) {
                return $this->handleException($passable, new FatalThrowableError($e));
            }
        };
    }

4. 重载父类carry

1、 parent::carry

 protected function carry()
    {
        return function ($stack, $pipe) {
            return function ($passable) use ($stack, $pipe) {
                try {
                    $slice = parent::carry();
                    $callable = $slice($stack, $pipe);
                    return $callable($passable);
                } catch (Exception $e) {
                    return $this->handleException($passable, $e);
                } catch (Throwable $e) {
                    return $this->handleException($passable, new FatalThrowableError($e));
                }
            };
        };
    }

5. 处理异常

1、bound
2、make
3、report
4、render
5、withException

  protected function handleException($passable, Exception $e)
    {
        if (! $this->container->bound(ExceptionHandler::class) ||
            ! $passable instanceof Request) {
            throw $e;
        }

        $handler = $this->container->make(ExceptionHandler::class);

        $handler->report($e);

        $response = $handler->render($passable, $e);

        if (method_exists($response, 'withException')) {
            $response->withException($e);
        }

        return $response;
    }

Illuminate\Pipeline\Pipeline

1. 引入

use Closure;//php匿名函数类
use RuntimeException;//php运行异常类
use Illuminate\Http\Request;//框架请求类
use Illuminate\Contracts\Container\Container;//框架容器接口
use Illuminate\Contracts\Support\Responsable;//框架响应接口
use Illuminate\Contracts\Pipeline\Pipeline as PipelineContract;//框架管道接口

2. 成员变量

    protected $container;//容器
    protected $passable;//正在通过管道的对象
    protected $pipes = [];//管道阵列
    protected $method = 'handle';//调用每个管道的方法

3. 构造函数

public function __construct(Container $container = null)
    {
        $this->container = $container;//传入容器(应用)
    }

4. 设置通过管道发送的对象

 public function send($passable)
    {
        $this->passable = $passable;//传入的Illuminate\Http\Request

        return $this;
    }

5. 管道数组

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

6. 设置调用管道的方法

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

7. 使用最终回调运行管道

1、array_reduce
2、carry(走的是子类重载的carry方法)
3、prepareDestination(走的是子类重载的prepareDestination的方法)

 public function then(Closure $destination)
    {
        $pipeline = array_reduce(
            array_reverse($this->pipes), //翻转数组
            $this->carry(),//需要执行的自定义函数
            $this->prepareDestination($destination)//参数 carry里边的$stack参数
        );
        return $pipeline($this->passable);//相当于执行dispatchToRouter($request)
    }

8. carry

1、parsePipeString

    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)) {
                    [$name, $parameters] = $this->parsePipeString($pipe);
                    $pipe = $this->getContainer()->make($name);//解析中间件
                    $parameters = array_merge([$passable, $stack], $parameters);//合并参数
                } else {
                    $parameters = [$passable, $stack];
                }
                $response = method_exists($pipe, $this->method)//判断是否存在方法
                                ? $pipe->{$this->method}(...$parameters)//执行
                                : $pipe(...$parameters);//实例
                return $response instanceof Responsable
                            ? $response->toResponse($this->container->make(Request::class))//返回响应体
                            : $response;
            };
        };
    }

9. 得到最后匿名函数

 protected function prepareDestination(Closure $destination)
    {
        return function ($passable) use ($destination) {
            return $destination($passable);//返回匿名函数 
        };
    }

10. 解析传入的管道字符串(中间件名称)

    protected function parsePipeString($pipe)
    {
        [$name, $parameters] = array_pad(explode(':', $pipe, 2), 2, []);

        if (is_string($parameters)) {
            $parameters = explode(',', $parameters);
        }
        return [$name, $parameters];
    }

11. 获取当前容器

    protected function getContainer()
    {
        if (! $this->container) {
            throw new RuntimeException('A container instance has not been passed to the Pipeline.');
        }
        return $this->container;
    }
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!