实际业务开发中可能遇到想给路由定义标签的场景,只有一个name()方法不够用的。下面是一种尝试
源码分析
定义路由使用的类实际使用的是Illuminate\Routing\Router
class Router implements RegistrarContract, BindingRegistrar{use Macroable {__call as macroCall;///关键代码1}........./*** Dynamically handle calls into the router instance.** @param string $method* @param array $parameters* @return mixed*/public function __call($method, $parameters){if (static::hasMacro($method)) {return $this->macroCall($method, $parameters);//关键代码2}if ($method === 'middleware') {return (new RouteRegistrar($this))->attribute($method, is_array($parameters[0]) ? $parameters[0] : $parameters);}return (new RouteRegistrar($this))->attribute($method, $parameters[0]);}
Illuminate\Support\Traits\Macroable
<?phpnamespace Illuminate\Support\Traits;use Closure;use ReflectionClass;use ReflectionMethod;use BadMethodCallException;trait Macroable{/*** The registered string macros.** @var array*/protected static $macros = [];/*** Register a custom macro.** @param string $name* @param object|callable $macro** @return void*/public static function macro($name, $macro){static::$macros[$name] = $macro;//注意这里value是objecj 或者callable}/*** Mix another object into the class.** @param object $mixin* @param bool $replace* @return void** @throws \ReflectionException*/public static function mixin($mixin, $replace = true){$methods = (new ReflectionClass($mixin))->getMethods(ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED);foreach ($methods as $method) {if ($replace || ! static::hasMacro($method->name)) {$method->setAccessible(true);static::macro($method->name, $method->invoke($mixin));//invoke直接执行方法,结合macro可以看到这里应该返回一个回调函数}}}/*** Checks if macro is registered.** @param string $name* @return bool*/public static function hasMacro($name){return isset(static::$macros[$name]);}/*** Dynamically handle calls to the class.** @param string $method* @param array $parameters* @return mixed** @throws \BadMethodCallException*/public static function __callStatic($method, $parameters){if (! static::hasMacro($method)) {throw new BadMethodCallException(sprintf('Method %s::%s does not exist.', static::class, $method));}$macro = static::$macros[$method];if ($macro instanceof Closure) {return call_user_func_array(Closure::bind($macro, null, static::class), $parameters);}return $macro(...$parameters);}/*** Dynamically handle calls to the class.** @param string $method* @param array $parameters* @return mixed** @throws \BadMethodCallException*/public function __call($method, $parameters){if (! static::hasMacro($method)) {throw new BadMethodCallException(sprintf('Method %s::%s does not exist.', static::class, $method));}$macro = static::$macros[$method];//这里执行注册过的回调函数if ($macro instanceof Closure) {return call_user_func_array($macro->bindTo($this, static::class), $parameters);}return $macro(...$parameters);}}
实现步骤
创建扩展类
新建App\Light\Mixin\MixinRoute
namespace App\Light\Mixin;class MixinRoute{/*** @return \Closure*/public function tag(){//这里返回一个closurereturn function ($tag) {//这里的$this就是route本身$this->tag = $tag;return $this;};}/*** @return \Closure*/public function getTag(){//这里返回一个closurereturn function () {//直接获取route新增的属性return $this->tag;};}}
创建服务提供者
<?phpnamespace App\Light\Mixin;use Illuminate\Routing\Route;use Illuminate\Support\ServiceProvider;class MixinServiceProvider extends ServiceProvider{public function register(){Route::mixin(new MixinRoute());//注册扩展route类}}
注册服务提供者
config/app.php中加入
//mixin服务提供者App\Light\Mixin\MixinServiceProvider::class,
使用方法
修改路由定义文件
Route::get('/', [App\Http\Controllers\WelcomeController::class, 'index'])->name('欢迎页')->tag('这里是标记');//这里使用扩展方法
查看全部路由
dd(Route::getRoutes());
单个路由
dd(Route::getCurrentRoute()->getTag());
