Analysis of middleware source code based on laravel5.2
在laravel5.2中,Http的主要作用就是过滤Http请求(php aritsan
是没有中间件机制的),同时也让系统的层次(Http过滤层)更明确,使用起来也很优雅。但实现中间件的代码却很复杂,下面就来具分析下有关中间件的源码的内容。
中间件源码
中间件本身分为两种,一种是所有http的,另一种则是针对route的。一个有中间件的请求周期是:Request得先经过Http中间件,才能进行Router,再经过Requset所对应Route的Route中间件, 最后才会进入相应的Controller代码。laravel把请求分为了两种:http和console。不同的请求方式用它自己的Kernel
来驱动Application
。Http请求则是通过\Illuminate\Foundation\Http\Kernel
类来驱动,它定义了所有的中间件,其父类\Illuminate\Foundation\Http\Kernel::handle
就是对请求进行处理的入口了
Http中间件
跟踪入口handle()
方法,很容易发现该函数(\Illuminate\Foundation\Http\Kernel::sendRequestThroughRouter
):
protected function sendRequestThroughRouter($request) { $this->app->instance('request', $request); Facade::clearResolvedInstance('request'); $this->bootstrap(); return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter()); }
该函数会把Requset分发到Router(通过方法名就知道了), 主要的逻辑则是通过\Illuminate\Routing\Pipeline
完成的, 作用就是让Requset通过Http中间件的检测,然后再到达Router。这里的代码看起来很优雅,但不是很好理解。所以,了解Pipeline
的运行机制就会明白中间件的使用。
Pipeline的运行实现
Pipleline
基类是\Illuminate\Pipeline\Pipeline
,它的执行在then
方法:
public function then(Closure $destination) { $firstSlice = $this->getInitialSlice($destination); $pipes = array_reverse($this->pipes); return call_user_func( array_reduce($pipes, $this->getSlice(), $firstSlice), $this->passable ); }
了解这段代码执行的意图,必须要知道array_reduce()做了什么。 为了清楚array_reduce
怎么运行的,先把array_reduce
重写一次:
//将数组中的元素,依次执行$func函数,且上一次的$func的返回值作为下一次调用$func的第一个参数输入 function array_reduce_back($arr, callable $func, $firstResult = null) { $result = $firstResult; foreach ($arr as $v) { $result = $func($result, $v); } return $result; }
所以,源代码中的$func
是getSlice()
,它返回的是一个回调函数:function($passable) use ($stack, $pipe){...}
($stack
和$pipe
被输入的具体值代替),也就是说作为上一次返回结果输入到下一次$func
的第一个参数是上述的回调函数,如此循环,当数组遍历完成,array_reduce
就返回的是一个回调函数,现在关键就是了解这个回调函数是什么样子,又如何执行?为方便讨论,可分析下面的代码:
call_user_func( array_reduce([1, 2, 3], $this->getSlice(), $firstSlice), $this->passable );
执行说明:
1.$result_0
是初始化的值 ,为$firstSlice
,即是\Illuminate\Pipeline\Pipeline::getInitialSlice
的返回回调
2.每遍历一个元素,都会执行\Illuminate\Pipeline\Pipeline::getSlice
的回调,同时也会返回一个回调
3.$result
中的具体执行代码都在getSlice()
中
4.最后的array_reduce
返回结果是$result_3
,是一个有多层闭包的回调函数
5.执行的是call_user_func($result_3, $this->passable)
,即执行function($this->passable) use ($result_2, 3){...}
至此已经清楚了then()
是如何运行的了,要继续下去,则需再搞定回调函数到底怎么执行的.现在再跟着sendRequestThroughRouter
中的Pipeline
走,看它是如何执行的。
// 把具体的参数带进来 return (new Pipeline($this->app)) ->send($request) ->through(['\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode']) ->then($this->dispatchToRouter());
用上面的所分析的Pipeline
执行过程,很快就会分析出最后执行的是
function($requset) use (\Illuminate\Foundation\Http\Kernel::dispatchToRouter(), '\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode') { if ($pipe instanceof Closure) { return call_user_func($pipe, $passable, $stack); } // $name和$parameters很容易得到 // $name = '\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode'; // $parameters = []; list($name, $parameters) = $this->parsePipeString($pipe); // 执行的就是\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::handle($request, \Illuminate\Foundation\Http\Kernel::dispatchToRouter()) return call_user_func_array([$this->container->make($name), $this->method], array_merge([$passable, $stack], $parameters)); }
逻辑处理已经到了\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::handle
,其代码是:
public function handle($request, Closure $next) { if ($this->app->isDownForMaintenance()) { throw new HttpException(503); } return $next($request); }
这里,它处理了这个中间件所需要过滤的条件,同时执行了$next($request)
,即\Illuminate\Foundation\Http\Kernel::dispatchToRouter()
, 这样,就把Request转到了Router中,也就完成了Http中间件的所有处理工作,而$next($request)
是每个中间件都不可少的操作,因为在回调中嵌套了回调,就是靠中间件把Request
传递到下一个回调中,也就会解析到下一个中间件,直到最后一个。紧跟上面的已分析的Pipeline
执行过程,讲其补充完整:
6.执行$result_3中的回调,getSlice
实例化中间件,执行其handle
,在中间件处理中执行回调
7.回调中还嵌套回调的,每个中间件中都需有执行回调的代码$next($request)
,才能保证回调中的回调会执行,执行的顺序就是3::handel,2::handel,1::handel,$first
8.最里面一层,一定是传递给then()的参数,then执行的就是最后一步
9.执行的顺序是由数组中的最后一个,向前,到then()的参数,为了使其执行顺序是数组中的第一个到最后一个,再到then()中的参数,then()方法中就做了一个反转array_reverse
Pipeline小结
现在,Pipeline的所有执行流程就都分析完了。实现代码真的很绕,但理解之后编写自定义的中间件应该就很容易了。现在再把Pipeline
的使用翻译成汉语,应该是这样的
// 使用管道,发送$request,使之通过middleware ,再到$func (new Pipeline($this->app))->send($request)->through($this->middleware)->then($func);
这样的代码不管是从语义上,还是使用上都很优雅,高!确实是高!再回到源码,Requset的流程就通过dispatchToRouter
进入到了Router
Route中间件
在Router中,\Illuminate\Routing\Router::dispatch
就承接了来自Http中间件的Requset, Router把Request分发到了具体的Route,再进行处理,主要代码如下:
public function dispatchToRoute(Request $request) { // 找到具体的路由对象,过程略 $route = $this->findRoute($request); $request->setRouteResolver(function () use ($route) { return $route; }); // 执行Request匹配到Route的事件,具体的代码在这里:\Illuminate\Foundation\Providers\FoundationServiceProvider::configureFormRequests $this->events->fire(new Events\RouteMatched($route, $request)); // 这里就运行路由中间件了 $response = $this->runRouteWithinStack($route, $request); return $this->prepareResponse($request, $response); } protected function runRouteWithinStack(Route $route, Request $request) { // 获取该路由上的中间件 // 简单就点可这样写: // $middleware = App::shouldSkipMiddleware() ? [] : $this->gatherRouteMiddlewares($route); $shouldSkipMiddleware = $this->container->bound('middleware.disable') && $this->container->make('middleware.disable') === true; $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddlewares($route); // 了解Pipeline后,这里就好理解了,应该是通过管道,发送$request,经过$middleware,再到then中的回调 return (new Pipeline($this->container)) ->send($request) ->through($middleware) ->then(function ($request) use ($route) { return $this->prepareResponse( $request, $route->run($request) ); }); }
如何获取Route中间件的,就可以跟gatherRouteMiddlewares
,这个代码并不难,很好跟。接下来,Request就到到达至于Controller, Request是如何到达Controller的代码就不难了,这里就不说了
Controller后执行中间件
成功获取Response后,在public/index.php
58行执行了$kernel->terminate($request, $response);
, 也就是在主要逻辑处理完成之后,再执行此代码,它实际上调用是的\Illuminate\Foundation\Http\Kernel::terminate
, 跟进去就很容易发现,它处理了这此请求所涉及到的中间件,并执行了各自的terminate
方法,到这里,中间件的另一个功能就展现出来了,就是主要逻辑完成之后的收尾工作.到这里为止,中间件就完成了它的使命(一个请求也就完成了)
如何使用中间件
在官方文档上讲解的很清楚注册中间
中间件小结
至此,中间件的实现逻辑与使用就清晰了.从执行的顺序来分,一个在Controller
之前,一个在Controller
之后,所以它一个很重要的作用就是可以让Controller
专注于自己的主要逻辑的职责更明确. 奇怪的是,但前后两种中间件的执行方式却不一样, \Illuminate\Foundation\Http\Kernel::terminate
,中间件的结束却没有使用Pipeline
, 而是直接foreach
.相同的工作却用两种代码来实现.现在看来,中间件本身并不复杂,但它带给了我两个启发,1.层次明确 2,Pipeline
所带来的优雅.
相关推荐:
Laravel 5.1框架中如何创建自定义Artisan控制台命令
The above is the detailed content of Analysis of middleware source code based on laravel5.2. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

Both Django and Laravel are full-stack frameworks. Django is suitable for Python developers and complex business logic, while Laravel is suitable for PHP developers and elegant syntax. 1.Django is based on Python and follows the "battery-complete" philosophy, suitable for rapid development and high concurrency. 2.Laravel is based on PHP, emphasizing the developer experience, and is suitable for small to medium-sized projects.

How does Laravel play a role in backend logic? It simplifies and enhances backend development through routing systems, EloquentORM, authentication and authorization, event and listeners, and performance optimization. 1. The routing system allows the definition of URL structure and request processing logic. 2.EloquentORM simplifies database interaction. 3. The authentication and authorization system is convenient for user management. 4. The event and listener implement loosely coupled code structure. 5. Performance optimization improves application efficiency through caching and queueing.

Laravel is a PHP framework for easy building of web applications. It provides a range of powerful features including: Installation: Install the Laravel CLI globally with Composer and create applications in the project directory. Routing: Define the relationship between the URL and the handler in routes/web.php. View: Create a view in resources/views to render the application's interface. Database Integration: Provides out-of-the-box integration with databases such as MySQL and uses migration to create and modify tables. Model and Controller: The model represents the database entity and the controller processes HTTP requests.

PHP and Laravel are not directly comparable, because Laravel is a PHP-based framework. 1.PHP is suitable for small projects or rapid prototyping because it is simple and direct. 2. Laravel is suitable for large projects or efficient development because it provides rich functions and tools, but has a steep learning curve and may not be as good as pure PHP.

LaravelisabackendframeworkbuiltonPHP,designedforwebapplicationdevelopment.Itfocusesonserver-sidelogic,databasemanagement,andapplicationstructure,andcanbeintegratedwithfrontendtechnologieslikeVue.jsorReactforfull-stackdevelopment.

Laravel provides a comprehensive Auth framework for implementing user login functions, including: Defining user models (Eloquent model), creating login forms (Blade template engine), writing login controllers (inheriting Auth\LoginController), verifying login requests (Auth::attempt) Redirecting after login is successful (redirect) considering security factors: hash passwords, anti-CSRF protection, rate limiting and security headers. In addition, the Auth framework also provides functions such as resetting passwords, registering and verifying emails. For details, please refer to the Laravel documentation: https://laravel.com/doc

Want to learn the Laravel framework, but suffer from no resources or economic pressure? This article provides you with free learning of Laravel, teaching you how to use resources such as online platforms, documents and community forums to lay a solid foundation for your PHP development journey from getting started to master.

In this era of continuous technological advancement, mastering advanced frameworks is crucial for modern programmers. This article will help you improve your development skills by sharing little-known techniques in the Laravel framework. Known for its elegant syntax and a wide range of features, this article will dig into its powerful features and provide practical tips and tricks to help you create efficient and maintainable web applications.
