当前位置: 首页 > 后端技术 > PHP

laravel中间件原理_0

时间:2023-03-29 19:40:04 PHP

其实我不是很喜欢laravel。它很笨重,设计过度,ide不友好,非常笨重。我是极简主义的追随者,我很反感这种把一堆大东西建起来,像koa,很对我的胃口。极简,再简单不过了,四个文件,每个文件加上空白和注释不超过700行代码。自从看到tj大师写的co,就崇拜到了极点。这是艺术家编写的代码。反观laravel没胃口,但是psr提出的中间件也只好采用laravel的中间件形式作为标签提案。老实说,我打从心底拒绝。该提案为他人提案,一票反对无效。花了点时间把laravel里面的一堆乱七八糟的砖挑出来,执行laravel中间的逻辑,记得整理一下。中间执行代码片段:/***通过中间件/路由器发送给定的请求。**@param\Illuminate\Http\Request$request*@return\Illuminate\Http\Response*/保护函数sendRequestThroughRouter($request){$this->app->instance('request',$request);Facade::clearResolvedInstance('request');$this->bootstrap();return(newPipeline($this->app))->send($request)->through($this->app->shouldSkipMiddleware()?[]:$this->middleware)->then($this-)>dispatchToRouter());}Laravel处理中间件路由的代码依赖一个让人看着不舒服的管道类。下面是pipe和核心代码:publicfunctionthen(Closure$destination){$pipeline=array_reduce(array_reverse($this->pipes),$this->carry(),$this->prepareDestination($destination));return$pipeline($this->passable);}/***获取最后一块Closure洋葱。**@param\Closure$destination*@return\Closure*/protectedfunctionprepareDestination(Closure$destination){returnfunction($passable)use($destination){return$destination($passable);}};}/***获取代表应用程序洋葱切片的闭包。**@return\Closure*/protectedfunctioncarry(){returnfunction($stack,$pipe){//@1返回函数($passable)use($stack,$pipe){//@2if(is_callable($pipe)){//如果管道是闭包的一个实例,我们将直接调用它,否则我们将解析容器外的管道并调用它//适当的方法和参数,将结果返回出来。返回$pipe($passable,$stack);}elseif(!is_object($pipe)){list($name,$parameters)=$this->parsePipeString($pipe);//如果管道是一个字符串,我们将解析该字符串并将类从依赖注入容器中解析出来。然后我们可以构建一个可调用对象并//执行提供所需参数的管道函数。$pipe=$this->getContainer()->make($name);$parameters=array_merge([$passable,$stack],$parameters);}else{//如果管道已经是一个对象,我们将创建一个可调用对象并将其按原样传递给//管道。不需要做任何额外的解析和格式化//因为我们得到的对象已经是一个完全实例化的对象。$参数=[$passable,$stack];}返回method_exists($pipe,$this->method)?$pipe->{$this->method}(...$parameters):$pipe(...$参数);};};}thunk函数加上reduce,像我这种抽象菜鸟一眼就看出来了,卧槽~!仔细看会发现其实是递归的,一目了然。必须这样设计。当然对于用户来说也一样,或者说更过瘾,但是代码的可读性就另当别论了。很多人可能看着这样一段话,即使看起来再亮眼,也未必能看懂其中的原理。这里先说明一下:要想理解pipe的原理,首先要知道array_reduce这个函数。不熟悉的可以去官网文档看看。array_reduce每次都会从所有中间件中取一个到@1匿名函数到第二个参数$pipe。注意这里的$stack,它的初始值为$this->prepareDestination();,$stack会在接下来的遍历中变成@2匿名函数,其实@2匿名函数用过laravel的人都会调用它的只是你不知道而已。在我们写的中间件中,就是$next($request);经常被中间件调用。所以中间可以一个一个设置,一直调用,就是所谓的洋葱皮。这种逻辑可以写得简单明了。当然,这种写法是可以的。我只是抱怨它的可读性。如果你想知道更简单的方法,你可以看看我在couser中的实现。2017-11-07by捡桑