前言 只為學習
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;
}