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
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
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 协议》,转载必须注明作者和本文链接
推荐文章: