实际业务开发中可能遇到想给路由定义标签的场景,只有一个name()方法不够用的。下面是一种尝试

源码分析

定义路由使用的类实际使用的是Illuminate\Routing\Router

  1. class Router implements RegistrarContract, BindingRegistrar
  2. {
  3. use Macroable {
  4. __call as macroCall;///关键代码1
  5. }
  6. ...
  7. ...
  8. ...
  9. /**
  10. * Dynamically handle calls into the router instance.
  11. *
  12. * @param string $method
  13. * @param array $parameters
  14. * @return mixed
  15. */
  16. public function __call($method, $parameters)
  17. {
  18. if (static::hasMacro($method)) {
  19. return $this->macroCall($method, $parameters);//关键代码2
  20. }
  21. if ($method === 'middleware') {
  22. return (new RouteRegistrar($this))->attribute($method, is_array($parameters[0]) ? $parameters[0] : $parameters);
  23. }
  24. return (new RouteRegistrar($this))->attribute($method, $parameters[0]);
  25. }

Illuminate\Support\Traits\Macroable

  1. <?php
  2. namespace Illuminate\Support\Traits;
  3. use Closure;
  4. use ReflectionClass;
  5. use ReflectionMethod;
  6. use BadMethodCallException;
  7. trait Macroable
  8. {
  9. /**
  10. * The registered string macros.
  11. *
  12. * @var array
  13. */
  14. protected static $macros = [];
  15. /**
  16. * Register a custom macro.
  17. *
  18. * @param string $name
  19. * @param object|callable $macro
  20. *
  21. * @return void
  22. */
  23. public static function macro($name, $macro)
  24. {
  25. static::$macros[$name] = $macro;//注意这里value是objecj 或者callable
  26. }
  27. /**
  28. * Mix another object into the class.
  29. *
  30. * @param object $mixin
  31. * @param bool $replace
  32. * @return void
  33. *
  34. * @throws \ReflectionException
  35. */
  36. public static function mixin($mixin, $replace = true)
  37. {
  38. $methods = (new ReflectionClass($mixin))->getMethods(
  39. ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED
  40. );
  41. foreach ($methods as $method) {
  42. if ($replace || ! static::hasMacro($method->name)) {
  43. $method->setAccessible(true);
  44. static::macro($method->name, $method->invoke($mixin));//invoke直接执行方法,结合macro可以看到这里应该返回一个回调函数
  45. }
  46. }
  47. }
  48. /**
  49. * Checks if macro is registered.
  50. *
  51. * @param string $name
  52. * @return bool
  53. */
  54. public static function hasMacro($name)
  55. {
  56. return isset(static::$macros[$name]);
  57. }
  58. /**
  59. * Dynamically handle calls to the class.
  60. *
  61. * @param string $method
  62. * @param array $parameters
  63. * @return mixed
  64. *
  65. * @throws \BadMethodCallException
  66. */
  67. public static function __callStatic($method, $parameters)
  68. {
  69. if (! static::hasMacro($method)) {
  70. throw new BadMethodCallException(sprintf(
  71. 'Method %s::%s does not exist.', static::class, $method
  72. ));
  73. }
  74. $macro = static::$macros[$method];
  75. if ($macro instanceof Closure) {
  76. return call_user_func_array(Closure::bind($macro, null, static::class), $parameters);
  77. }
  78. return $macro(...$parameters);
  79. }
  80. /**
  81. * Dynamically handle calls to the class.
  82. *
  83. * @param string $method
  84. * @param array $parameters
  85. * @return mixed
  86. *
  87. * @throws \BadMethodCallException
  88. */
  89. public function __call($method, $parameters)
  90. {
  91. if (! static::hasMacro($method)) {
  92. throw new BadMethodCallException(sprintf(
  93. 'Method %s::%s does not exist.', static::class, $method
  94. ));
  95. }
  96. $macro = static::$macros[$method];
  97. //这里执行注册过的回调函数
  98. if ($macro instanceof Closure) {
  99. return call_user_func_array($macro->bindTo($this, static::class), $parameters);
  100. }
  101. return $macro(...$parameters);
  102. }
  103. }

实现步骤

创建扩展类

新建App\Light\Mixin\MixinRoute

  1. namespace App\Light\Mixin;
  2. class MixinRoute
  3. {
  4. /**
  5. * @return \Closure
  6. */
  7. public function tag()
  8. {
  9. //这里返回一个closure
  10. return function ($tag) {
  11. //这里的$this就是route本身
  12. $this->tag = $tag;
  13. return $this;
  14. };
  15. }
  16. /**
  17. * @return \Closure
  18. */
  19. public function getTag()
  20. {
  21. //这里返回一个closure
  22. return function () {
  23. //直接获取route新增的属性
  24. return $this->tag;
  25. };
  26. }
  27. }

创建服务提供者

  1. <?php
  2. namespace App\Light\Mixin;
  3. use Illuminate\Routing\Route;
  4. use Illuminate\Support\ServiceProvider;
  5. class MixinServiceProvider extends ServiceProvider
  6. {
  7. public function register()
  8. {
  9. Route::mixin(new MixinRoute());//注册扩展route类
  10. }
  11. }

注册服务提供者

config/app.php中加入

  1. //mixin服务提供者
  2. App\Light\Mixin\MixinServiceProvider::class,

使用方法

修改路由定义文件

  1. Route::get('/', [App\Http\Controllers\WelcomeController::class, 'index'])
  2. ->name('欢迎页')
  3. ->tag('这里是标记');//这里使用扩展方法

查看全部路由

  1. dd(Route::getRoutes());

image.png

单个路由

  1. dd(Route::getCurrentRoute()->getTag());