Laravel 路由源码分析

前言 只为学习

Illuminate\Routing\Router 分析

1. 引入

use Closure;//php 匿名类
use ArrayObject;//
use JsonSerializable;//
use Illuminate\Support\Str;//框架支持的str类
use Illuminate\Http\Request;//框架请求类
use Illuminate\Http\Response;//框架响应类
use Illuminate\Http\JsonResponse;//框架json响应类
use Illuminate\Support\Collection;//框架支持的集合类
use Illuminate\Container\Container;//框架容器基类
use Illuminate\Database\Eloquent\Model;//框架数据库模型基类
use Illuminate\Support\Traits\Macroable;//框架 Macroable  Traits
use Illuminate\Contracts\Support\Jsonable;//框架契约json接口
use Illuminate\Contracts\Events\Dispatcher;//框架契约时间调度接口
use Illuminate\Contracts\Support\Arrayable;//框架契约数组接口
use Illuminate\Contracts\Support\Responsable;//框架契约响应体接口
use Illuminate\Contracts\Routing\BindingRegistrar;//框架契约路由绑定寄存器接口
use Psr\Http\Message\ResponseInterface as PsrResponseInterface;//
use Illuminate\Contracts\Routing\Registrar as RegistrarContract;//框架契约路由寄存器接口
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;//
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;

2. 声明router类 实现接口

class Router implements RegistrarContract, BindingRegistrar
{
    use Macroable {
        __call as macroCall;//使用Macroable  Traits 并且重名称__call 方法
    }

    /**
     * The event dispatcher instance.
     * 事件调度器实例
     * @var \Illuminate\Contracts\Events\Dispatcher
     */
    protected $events;

    /**
     * The IoC container instance.
     * 容器实例
     * @var \Illuminate\Container\Container
     */
    protected $container;

    /**
     * The route collection instance.
     * 路由集合实例
     * @var \Illuminate\Routing\RouteCollection
     */
    protected $routes;

    /**
     * The currently dispatched route instance.
     * 当前路由
     * @var \Illuminate\Routing\Route
     */
    protected $current;

    /**
     * The request currently being dispatched.
     * 当前请求
     * @var \Illuminate\Http\Request
     */
    protected $currentRequest;

    /**
     * All of the short-hand keys for middlewares.
     * 中间件
     * @var array
     */
    protected $middleware = [];

    /**
     * All of the middleware groups.
     * 中间件组
     * @var array
     */
    protected $middlewareGroups = [];

    /**
     * The priority-sorted list of middleware.
     *
     * Forces the listed middleware to always be in the given order.
     * 强制列出的中间件始终按给定顺序排列。
     * @var array
     */
    public $middlewarePriority = [];

    /**
     * The registered route value binders.
     * 注册路由绑定
     * @var array
     */
    protected $binders = [];

    /**
     * The globally available parameter patterns.
     * 全局可用参数模式
     * @var array
     */
    protected $patterns = [];

    /**
     * The route group attribute stack.
     * 路由组属性堆栈。
     * @var array
     */
    protected $groupStack = [];

    /**
     * All of the verbs supported by the router.
     * 路由器支持的所有动作
     * @var array
     */
    public static $verbs = ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'];

3. 构造方法

//注册一个新的router 实例
public function __construct(Dispatcher $events, Container $container = null)
    {
        $this->events = $events;
        $this->routes = new RouteCollection;
        $this->container = $container ?: new Container;
    }

4. get 向路由器注册新的get 路由

1、addRoute

public function get($uri, $action = null)
    {
        return $this->addRoute(['GET', 'HEAD'], $uri, $action);
    }

5. post 向路由器注册新的post 路由

1、addRoute

public function post($uri, $action = null)
    {
        return $this->addRoute('POST', $uri, $action);
    }

6. put 向路由器注册新的put 路由

1、addRoute

public function put($uri, $action = null)
    {
        return $this->addRoute('PUT', $uri, $action);
    }

7. patch 向路由器注册新的patch 路由

1、addRoute

public function patch($uri, $action = null)
    {
        return $this->addRoute('PATCH', $uri, $action);
    }

8. delete 向路由器注册新的delete路由

1、addRoute

public function delete($uri, $action = null)
    {
        return $this->addRoute('DELETE', $uri, $action);
    }

9. options 向路由器注册新的options 路由

1、addRoute

public function options($uri, $action = null)
    {
        return $this->addRoute('OPTIONS', $uri, $action);
    }

10. any 注册响应所有动词的新路由。

1、addRoute

public function any($uri, $action = null)
    {
        return $this->addRoute(self::$verbs, $uri, $action);
    }

11. fallback 注册回退路由

1、addRoute

public function fallback($action)
    {
        $placeholder = 'fallbackPlaceholder';

        return $this->addRoute(
            'GET', "{{$placeholder}}", $action
        )->where($placeholder, '.*')->fallback();
    }

12. redirect 创建重定向路由

1、any
2、defaults

public function redirect($uri, $destination, $status = 302)
    {
        return $this->any($uri, '\Illuminate\Routing\RedirectController')
                ->defaults('destination', $destination)
                ->defaults('status', $status);
    }

13. permanentRedirect 创建从一个URI到另一个URI的永久重定向

1、redirect

public function permanentRedirect($uri, $destination)
    {
        return $this->redirect($uri, $destination, 301);
    }

14. view 注册返回视图的新路由。

1、match
2、defaults

public function view($uri, $view, $data = [])
    {
        return $this->match(['GET', 'HEAD'], $uri, '\Illuminate\Routing\ViewController')
                ->defaults('view', $view)
                ->defaults('data', $data);
    }

15. match 注册多个动作的新路由

1、addRoute

public function match($methods, $uri, $action = null)
    {
        return $this->addRoute(array_map('strtoupper', (array) $methods), $uri, $action);
    }

16. resources 注册一个资源控制器数组。

1、resource

public function resources(array $resources, array $options = [])
    {
        foreach ($resources as $name => $controller) {
            $this->resource($name, $controller, $options);
        }
    }

17. resource 添加资源路由到控制器

public function resource($name, $controller, array $options = [])
    {
        if ($this->container && $this->container->bound(ResourceRegistrar::class)) {
            $registrar = $this->container->make(ResourceRegistrar::class);
        } else {
            $registrar = new ResourceRegistrar($this);//   Illuminate\Routing\ResourceRegistrar
        }
        // \Illuminate\Routing\PendingResourceRegistration
        return new PendingResourceRegistration(
            $registrar, $name, $controller, $options
        );
    }

18. apiResources 注册api路由数组

1、apiResource

public function apiResources(array $resources, array $options = [])
    {
        foreach ($resources as $name => $controller) {
            $this->apiResource($name, $controller, $options);
        }
    }

19. apiResource 注册api路由到控制器

1、resource

public function apiResource($name, $controller, array $options = [])
    {
        $only = ['index', 'show', 'store', 'update', 'destroy'];

        if (isset($options['except'])) {
            $only = array_diff($only, (array) $options['except']);
        }
        return $this->resource($name, $controller, array_merge([
            'only' => $only,
        ], $options));
    }

20. group 创建路由组

1、updateGroupStack
2、

public function group(array $attributes, $routes)
    {
        $this->updateGroupStack($attributes);// 更新堆栈
        $this->loadRoutes($routes);
        array_pop($this->groupStack);//删除最后一个堆栈数据
    }

21. updateGroupStack

1、

protected function updateGroupStack(array $attributes)
    {
        if (! empty($this->groupStack)) {
            $attributes = $this->mergeWithLastGroup($attributes);
        }
        $this->groupStack[] = $attributes;
    }

22. mergeWithLastGroup 将给定数组与最后一个组堆栈合并

public function mergeWithLastGroup($new)
    {
        return RouteGroup::merge($new, end($this->groupStack));
    }

23. loadRoutes 加载路由数据

protected function loadRoutes($routes)
    {
        if ($routes instanceof Closure) {
            $routes($this);
        } else {
            $router = $this;

            require $routes;
        }
    }

24. getLastGroupPrefix 从堆栈上的最后一个组获取前缀

public function getLastGroupPrefix()
    {
        if (! empty($this->groupStack)) {
            $last = end($this->groupStack);

            return $last['prefix'] ?? '';
        }

        return '';
    }

25. addRoute

1、createRoute
2、add

public function addRoute($methods, $uri, $action)
    {
        return $this->routes->add($this->createRoute($methods, $uri, $action));
    }

26. createRoute 创建路由

1、actionReferencesController
2、convertToControllerAction
3、newRoute
4、prefix
5、hasGroupStack
6、mergeGroupAttributesIntoRoute
7、addWhereClausesToRoute

protected function createRoute($methods, $uri, $action)
    {
        //确定操作是否路由到控制器。
        if ($this->actionReferencesController($action)) {
        //将基于控制器的路由操作添加到操作数组
            $action = $this->convertToControllerAction($action);
        }
        //
        $route = $this->newRoute(
            $methods, $this->prefix($uri), $action
        );

        if ($this->hasGroupStack()) {
            $this->mergeGroupAttributesIntoRoute($route);
        }

        $this->addWhereClausesToRoute($route);

        return $route;
    }

27. actionReferencesController 确定操作是否路由到控制器。

    protected function actionReferencesController($action)
    {
        if (! $action instanceof Closure) {
            return is_string($action) || (isset($action['uses']) && is_string($action['uses']));
        }
        return false;
    }

28. convertToControllerAction 将基于控制器的路由操作添加到操作数组

1、prependGroupNamespace

protected function convertToControllerAction($action)
    {
        if (is_string($action)) {
            $action = ['uses' => $action];
        }
        if (! empty($this->groupStack)) {
            $action['uses'] = $this->prependGroupNamespace($action['uses']);
        }
        $action['controller'] = $action['uses'];

        return $action;
    }

29. prependGroupNamespace 最后一个组命名空间前置到use子句上

protected function prependGroupNamespace($class)
    {
        $group = end($this->groupStack);

        return isset($group['namespace']) && strpos($class, '\\') !== 0
                ? $group['namespace'].'\\'.$class : $class;
    }

30. newRoute 创建路由对象

protected function newRoute($methods, $uri, $action)
    {
        return (new Route($methods, $uri, $action))
                    ->setRouter($this)
                    ->setContainer($this->container);
    }

31. prefix 给定的url前缀

protected function prefix($uri)
    {
        return trim(trim($this->getLastGroupPrefix(), '/').'/'.trim($uri, '/'), '/') ?: '/';
    }

32. addWhereClausesToRoute 添加条款删除

protected function addWhereClausesToRoute($route)
    {
        $route->where(array_merge(
            $this->patterns, $route->getAction()['where'] ?? []
        ));
        return $route;
    }

33. mergeGroupAttributesIntoRoute 将组堆栈与控制器操作合并

protected function mergeGroupAttributesIntoRoute($route)
    {
        $route->setAction($this->mergeWithLastGroup($route->getAction()));
    }

34. respondWithRoute 返回给定路由返回的响应

1、runRoute

public function respondWithRoute($name)
    {
        $route = tap($this->routes->getByName($name))->bind($this->currentRequest);

        return $this->runRoute($this->currentRequest, $route);
    }

35. dispatch 将请求发送到应用程序。

public function dispatch(Request $request)
    {
        $this->currentRequest = $request;

        return $this->dispatchToRoute($request);
    }

36. dispatchToRoute 将请求发送到路由并返回响应

1、runRoute
2、findRoute

public function dispatchToRoute(Request $request)
    {
        return $this->runRoute($request, $this->findRoute($request));
    }

37. findRoute 匹配路由

protected function findRoute($request)
    {
        $this->current = $route = $this->routes->match($request);

        $this->container->instance(Route::class, $route);

        return $route;
    }

38. runRoute 运行路由返回响应

1、prepareResponse
2、runRouteWithinStack

protected function runRoute(Request $request, Route $route)
    {
        $request->setRouteResolver(function () use ($route) {
            return $route;
        });

        $this->events->dispatch(new Events\RouteMatched($route, $request));

        return $this->prepareResponse($request,
            $this->runRouteWithinStack($route, $request)
        );
    }

39. runRouteWithinStack 在堆栈实例中运行给定的路由

1、gatherRouteMiddleware
2、prepareResponse

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()
                            );
                        });
    }

40. gatherRouteMiddleware 获取当前路由中间件

1、sortMiddleware

public function gatherRouteMiddleware(Route $route)
    {
        $middleware = collect($route->gatherMiddleware())->map(function ($name) {
            return (array) MiddlewareNameResolver::resolve($name, $this->middleware, $this->middlewareGroups);
        })->flatten();

        return $this->sortMiddleware($middleware);
    }

41. sortMiddleware 排序中间件

1、middlewarePriority

    protected function sortMiddleware(Collection $middlewares)
    {
        return (new SortedMiddleware($this->middlewarePriority, $middlewares))->all();
    }

42. prepareResponse 给定值响应实例

public function prepareResponse($request, $response)
    {
        return static::toResponse($request, $response);
    }

43. toResponse

public static function toResponse($request, $response)
    {
        if ($response instanceof Responsable) {
            $response = $response->toResponse($request);
        }

        if ($response instanceof PsrResponseInterface) {
            $response = (new HttpFoundationFactory)->createResponse($response);
        } elseif ($response instanceof Model && $response->wasRecentlyCreated) {
            $response = new JsonResponse($response, 201);
        } elseif (! $response instanceof SymfonyResponse &&
                   ($response instanceof Arrayable ||
                    $response instanceof Jsonable ||
                    $response instanceof ArrayObject ||
                    $response instanceof JsonSerializable ||
                    is_array($response))) {
            $response = new JsonResponse($response);
        } elseif (! $response instanceof SymfonyResponse) {
            $response = new Response($response);
        }

        if ($response->getStatusCode() === Response::HTTP_NOT_MODIFIED) {
            $response->setNotModified();
        }

        return $response->prepare($request);
    }

44. substituteBindings 将路由绑定替换到路由上

1、binders
2、performBinding

public function substituteBindings($route)
    {
        foreach ($route->parameters() as $key => $value) {
            if (isset($this->binders[$key])) {
                $route->setParameter($key, $this->performBinding($key, $value, $route));
            }
        }
        return $route;
    }

45. substituteImplicitBindings

public function substituteImplicitBindings($route)
    {
        ImplicitRouteBinding::resolveForRoute($this->container, $route);
    }

46. performBinding 调用给定键的绑定回调。

protected function performBinding($key, $value, $route)
    {
        return call_user_func($this->binders[$key], $value, $route);
    }

47. matched 注册路由匹配的事件侦听器

public function matched($callback)
    {
        $this->events->listen(Events\RouteMatched::class, $callback);
    }

48. getMiddleware 获取全局中间件

public function getMiddleware()
    {
        return $this->middleware;
    }

49. aliasMiddleware 设置中间件别名

public function aliasMiddleware($name, $class)
    {
        $this->middleware[$name] = $class;

        return $this;
    }

50. hasMiddlewareGroup 检测是否存在中间件组中

public function hasMiddlewareGroup($name)
    {
        return array_key_exists($name, $this->middlewareGroups);
    }

51. getMiddlewareGroups 获取中间件组

public function getMiddlewareGroups()
    {
        return $this->middlewareGroups;
    }

52. middlewareGroup 设置中间件组

public function middlewareGroup($name, array $middleware)
    {
        $this->middlewareGroups[$name] = $middleware;

        return $this;
    }

53. prependMiddlewareToGroup 头部插入中间件组

public function prependMiddlewareToGroup($group, $middleware)
    {
        if (isset($this->middlewareGroups[$group]) && ! in_array($middleware, $this->middlewareGroups[$group])) {
            array_unshift($this->middlewareGroups[$group], $middleware);
        }

        return $this;
    }

54. pushMiddlewareToGroup 尾部插入中间件组

public function pushMiddlewareToGroup($group, $middleware)
    {
        if (! array_key_exists($group, $this->middlewareGroups)) {
            $this->middlewareGroups[$group] = [];
        }

        if (! in_array($middleware, $this->middlewareGroups[$group])) {
            $this->middlewareGroups[$group][] = $middleware;
        }

        return $this;
    }

55. bind

public function bind($key, $binder)
    {
        $this->binders[str_replace('-', '_', $key)] = RouteBinding::forCallback(
            $this->container, $binder
        );
    }

56. model 为通配符注册模型绑定器

public function model($key, $class, Closure $callback = null)
    {
        $this->bind($key, RouteBinding::forModel($this->container, $class, $callback));
    }

57. getBindingCallback 获取绑定的回调函数

public function getBindingCallback($key)
    {
        if (isset($this->binders[$key = str_replace('-', '_', $key)])) {
            return $this->binders[$key];
        }
    }

58. getPatterns 全局匹配模式

    public function getPatterns()
    {
        return $this->patterns;
    }

59. pattern 设置全局匹配模式

public function pattern($key, $pattern)
    {
        $this->patterns[$key] = $pattern;
    }

60. patterns 批量设置全局匹配模式

public function patterns($patterns)
    {
        foreach ($patterns as $key => $pattern) {
            $this->pattern($key, $pattern);
        }
    }

61. hasGroupStack 判断路由组属性堆是否存在

public function hasGroupStack()
    {
        return ! empty($this->groupStack);
    }

62. getGroupStack 获取路由组属性堆

public function getGroupStack()
    {
        return $this->groupStack;
    }

63. input 获取当前请求参数

public function input($key, $default = null)
    {
        return $this->current()->parameter($key, $default);
    }

64. getCurrentRequest 获取当前请求

    public function getCurrentRequest()
    {
        return $this->currentRequest;
    }

65. getCurrentRoute 获取当前请求路由

public function getCurrentRoute()
    {
        return $this->current();
    }

66. current 获取当前请求路由

public function current()
    {
        return $this->current;
    }

67. has 检测路由是否存在

public function has($name)
    {
        $names = is_array($name) ? $name : func_get_args();

        foreach ($names as $value) {
            if (! $this->routes->hasNamedRoute($value)) {
                return false;
            }
        }

        return true;
    }

68. currentRouteName 当前路由名称

public function currentRouteName()
    {
        return $this->current() ? $this->current()->getName() : null;
    }

69. is

public function is(...$patterns)
    {
        return $this->currentRouteNamed(...$patterns);
    }

70. currentRouteNamed 确定当前路由是否符合模式

public function currentRouteNamed(...$patterns)
    {
        return $this->current() && $this->current()->named(...$patterns);
    }

71. currentRouteAction 获取当前请求路由控制器

public function currentRouteAction()
    {
        if ($this->current()) {
            return $this->current()->getAction()['controller'] ?? null;
        }
    }

72. uses “currentRouteuses”方法的别名

public function uses(...$patterns)
    {
        foreach ($patterns as $pattern) {
            if (Str::is($pattern, $this->currentRouteAction())) {
                return true;
            }
        }

        return false;
    }

73. currentRouteUses

public function currentRouteUses($action)
    {
        return $this->currentRouteAction() == $action;
    }

74. auth 为应用程序注册典型的身份验证路由

public function auth(array $options = [])
    {
        $this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
        $this->post('login', 'Auth\LoginController@login');
        $this->post('logout', 'Auth\LoginController@logout')->name('logout');
        if ($options['register'] ?? true) {
            $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
            $this->post('register', 'Auth\RegisterController@register');
        }
        if ($options['reset'] ?? true) {
            $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
            $this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
            $this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
            $this->post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update');
        }
        if ($options['verify'] ?? false) {
            $this->emailVerification();
        }
    }

75. emailVerification 注册邮箱验证路由

public function emailVerification()
    {
        $this->get('email/verify', 'Auth\VerificationController@show')->name('verification.notice');
        $this->get('email/verify/{id}', 'Auth\VerificationController@verify')->name('verification.verify');
        $this->get('email/resend', 'Auth\VerificationController@resend')->name('verification.resend');
    }

76. singularResourceParameters 将未映射的全局资源参数设置为单数

public function singularResourceParameters($singular = true)
    {
        ResourceRegistrar::singularParameters($singular);
    }

77. resourceParameters 设置全局资源参数映射

public function resourceParameters(array $parameters = [])
    {
        ResourceRegistrar::setParameters($parameters);
    }

78. resourceVerbs 获取或设置资源URI中使用的谓词

public function resourceVerbs(array $verbs = [])
    {
        return ResourceRegistrar::verbs($verbs);
    }

79. getRoutes 获取路由集合实例

public function getRoutes()
    {
        return $this->routes;
    }

80. setRoutes 设置路由集合实例

public function setRoutes(RouteCollection $routes)
    {
        foreach ($routes as $route) {
            $route->setRouter($this)->setContainer($this->container);
        }

        $this->routes = $routes;

        $this->container->instance('routes', $this->routes);
    }

81. 魔术方法

public function __call($method, $parameters)
    {
        if (static::hasMacro($method)) {
            return $this->macroCall($method, $parameters);
        }

        if ($method === 'middleware') {
            return (new RouteRegistrar($this))->attribute($method, is_array($parameters[0]) ? $parameters[0] : $parameters);
        }

        return (new RouteRegistrar($this))->attribute($method, $parameters[0]);
    }
本作品采用《CC 协议》,转载必须注明作者和本文链接
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

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