Laravel 路由執行
程式碼展示
protected function runRouteWithinStack(Route $route, Request $request)
{
$shouldSkipMiddleware = $this->container->bound(`middleware.disable`) &&
$this->container->make(`middleware.disable`) === true;
$middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route);
return (new Pipeline($this->container))
->send($request)
->through($middleware)
->then(function ($request) use ($route) {
return $this->prepareResponse(
$request, $route->run()
);
});
}
public function run()
{
$this->container = $this->container ?: new Container;
try {
// 控制器形式(Controller@Method)
if ($this->isControllerAction()) {
return $this->runController();
}
// 匿名函式形式
return $this->runCallable();
} catch (HttpResponseException $e) {
return $e->getResponse();
}
}
控制器形式處理
protected function runController()
{
return (new ControllerDispatcher($this->container))->dispatch(
$this, $this->getController(), $this->getControllerMethod()
);
}
public function getController()
{
$class = $this->parseControllerCallback()[0];
if (! $this->controller) {
$this->controller = $this->container->make($class);
}
return $this->controller;
}
protected function getControllerMethod()
{
return $this->parseControllerCallback()[1];
}
protected function parseControllerCallback()
{
return Str::parseCallback($this->action[`uses`]);
}
public static function parseCallback($callback, $default = null)
{
return static::contains($callback, `@`) ? explode(`@`, $callback, 2) : [$callback, $default];
}
// IlluminateRoutingControllerDispatcher
public function __construct(Container $container)
{
$this->container = $container;
}
public function dispatch(Route $route, $controller, $method)
{
// 控制器引數解析
$parameters = $this->resolveClassMethodDependencies(
$route->parametersWithoutNulls(), $controller, $method
);
if (method_exists($controller, `callAction`)) {
return $controller->callAction($method, $parameters);
}
return $controller->{$method}(...array_values($parameters));
}
public function parametersWithoutNulls()
{
// 返回過濾的從路徑或主機名解析出來的對應的引數陣列,類似 [`post`=>1,`comment`=>2]
return array_filter($this->parameters(), function ($p) {
return ! is_null($p);
});
}
protected function resolveClassMethodDependencies(array $parameters, $instance, $method)
{
// __invoke 方式呼叫
if (! method_exists($instance, $method)) {
return $parameters;
}
return $this->resolveMethodDependencies(
$parameters, new ReflectionMethod($instance, $method)
);
}
// 控制器的方法可以有自己的區別於路由引數的類型別引數,其他引數只能從路由獲取
public function resolveMethodDependencies(array $parameters, ReflectionFunctionAbstract $reflector)
{
$results = [];
$instanceCount = 0;
$values = array_values($parameters);
foreach ($reflector->getParameters() as $key => $parameter) {
// 類方法自己的類型別引數,嘗試例項化
$instance = $this->transformDependency(
$parameter, $parameters
);
if (! is_null($instance)) {
$instanceCount++;
$results[] = $instance;
} else { // 按照類方法的引數順序依次存放資料
$results[] = isset($values[$key - $instanceCount])
? $values[$key - $instanceCount] : $parameter->getDefaultValue();
}
}
return $results;
}
protected function transformDependency(ReflectionParameter $parameter, $parameters)
{
$class = $parameter->getClass();
// 類型別且沒有例項化,則通過服務容器解決引數的依賴關係,並進行例項化
if ($class && ! $this->alreadyInParameters($class->name, $parameters)) {
return $this->container->make($class->name);
}
}
protected function alreadyInParameters($class, array $parameters)
{
return ! is_null(Arr::first($parameters, function ($value) use ($class) {
return $value instanceof $class;
}));
}
public function callAction($method, $parameters)
{
return call_user_func_array([$this, $method], $parameters);
}
小結:
主要就是將路由獲取到的引數依次對應到控制器方法的引數,當然控制器方法可以有自己的類型別引數
匿名函式形式處理
protected function runCallable()
{
$callable = $this->action[`uses`];
// 一樣的處理方式
return $callable(...array_values($this->resolveMethodDependencies(
$this->parametersWithoutNulls(), new ReflectionFunction($this->action[`uses`])
)));
}
返回
即控制器的返回