Home>Article>PHP Framework> This article will help you thoroughly understand how Laravel works!

This article will help you thoroughly understand how Laravel works!

藏色散人
藏色散人 forward
2020-12-23 09:12:13 4610browse

The following is an introduction to the operating principle of Laravel from theLaravel Frameworktutorial column. I hope it will be helpful to friends in need!

Preface

Knowing it, knowing it, most people must be confused when they first come into contact with the framework. They don’t know how to implement it. There is no certain way. Basic knowledge of the framework, if you go directly to the source code of the framework, you will be directly discouraged. TheLaravelframework is a very excellentPHPframework. This article will help you understand it thoroughly. The operating principle of the framework will give you something to talk about (brag) during the interview. Learning and researching the source code of excellent frameworks will also help improve our own technology. Next, fasten your seat belts, experienced drivers are about to start driving! ! !

Preparatory knowledge

  • Be familiar with the basic knowledge of PHP, such as common array methods, the use of closure functions, and the use of magic methods
  • Familiar with PHP's reflection mechanism and dependency injection
  • Familiar with PHP namespace concepts and compose automatic loading
  • Familiar with common design patterns, including but not limited to singleton mode, factory mode, facade mode, registration Tree mode, decorator mode, etc.

Overview of operating principles

LaravelEntry file of the frameworkindex.php

1. Introduce automatic loadingautoload.phpfile

2. Create an application instance and complete it at the same time

基本绑定($this、容器类Container等等)、 基本服务提供者的注册(Event、log、routing)、 核心类别名的注册(比如db、auth、config、router等)

3. StartHttpRequest processing

make 方法从容器中解析指定的值为实际的类,比如 $app->make(Illuminate\Contracts\Http\Kernel::class); 解析出来 App\Http\Kernel handle 方法对 http 请求进行处理 实际上是 handle 中 sendRequestThroughRouter 处理 http 的请求 首先,将 request 绑定到共享实例 然后执行 bootstarp 方法,运行给定的引导类数组 $bootstrappers,这里是重点,包括了加载配置文件、环境变量、服务提供者、门面、异常处理、引导提供者等 之后,进入管道模式,经过中间件的处理过滤后,再进行用户请求的分发 在请求分发时,首先,查找与给定请求匹配的路由,然后执行 runRoute 方法,实际处理请求的时候 runRoute 中的 runRouteWithinStack 最后,经过 runRouteWithinStack 中的 run 方法,将请求分配到实际的控制器中,执行闭包或者方法,并得到响应结果

4. Return the processing result

Detailed source code analysis

1. Register the automatic loading class and implement Automatic loading of files

require __DIR__.'/../vendor/autoload.php';

2. Create an application container instanceApplication(this instance inherits from the container classContainer), and bind the core (web, command line, Exceptions) to facilitate parsing them when needed

$app = require_once __DIR__.'/../bootstrap/app.php';

app.phpThe file is as follows:

singleton( Illuminate\Contracts\Http\Kernel::class, App\Http\Kernel::class); // 绑定命令行kernel $app->singleton( Illuminate\Contracts\Console\Kernel::class, App\Console\Kernel::class); // 绑定异常处理 $app->singleton( Illuminate\Contracts\Debug\ExceptionHandler::class, App\Exceptions\Handler::class); // 返回应用实例 return $app;

3. When creating an application instance (Application.php) in the constructor, register the basic binding into the container, register all basic service providers, and register the core category name in the container

3.1, register the basic binding into the container Medium

/** * Register the basic bindings into the container. * * @return void */ protected function registerBaseBindings() { static::setInstance($this); $this->instance('app', $this); $this->instance(Container::class, $this); $this->singleton(Mix::class); $this->instance(PackageManifest::class, new PackageManifest( new Filesystem, $this->basePath(), $this->getCachedPackagesPath() )); # 注:instance方法为将...注册为共享实例,singleton方法为将...注册为共享绑定 }

3.2. Register all basic service providers (events, logs, routing)

protected function registerBaseServiceProviders() { $this->register(new EventServiceProvider($this)); $this->register(new LogServiceProvider($this)); $this->register(new RoutingServiceProvider($this)); }

3.3. Register the core category name in the container

4. The above completes the automatic loading of classes, service provider registration, binding of core classes, and binding of basic registrations

5. Start parsing the request ofhttp

index.php //5.1 $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); //5.2 $response = $kernel->handle( $request = Illuminate\Http\Request::capture());

5.1. The make method is to parse the given value from the container

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); 中的Illuminate\Contracts\Http\Kernel::class 是在index.php 中的$app = require_once __DIR__.'/../bootstrap/app.php';这里面进行绑定的,实际指向的就是App\Http\Kernel::class这个类

5.2. Here the http request is processed

$response = $kernel->handle( $request = Illuminate\Http\Request::capture());

Enter$kernelIn the represented classApp\Http\Kernel.php, we can see that it only defines some middleware-related content, and there is no handle method

Let’s go to its parent Find the handle method in classuse Illuminate\Foundation\Http\Kernel as HttpKernel;, you can see that the handle method is like this

public function handle($request){ try { $request->enableHttpMethodParameterOverride(); // 最核心的处理http请求的地方【6】 $response = $this->sendRequestThroughRouter($request); } catch (Exception $e) { $this->reportException($e); $response = $this->renderException($request, $e); } catch (Throwable $e) { $this->reportException($e = new FatalThrowableError($e)); $response = $this->renderException($request, $e); } $this->app['events']->dispatch( new Events\RequestHandled($request, $response) ); return $response;}

6. ProcessHttprequest ( Bindrequestto the shared instance and use pipeline mode to handle user requests)

vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php的handle方法// 最核心的处理http请求的地方$response = $this->sendRequestThroughRouter($request);protected function sendRequestThroughRouter($request){ // 将请求$request绑定到共享实例 $this->app->instance('request', $request); // 将请求request从已解析的门面实例中清除(因为已经绑定到共享实例中了,没必要再浪费资源了) Facade::clearResolvedInstance('request'); // 引导应用程序进行HTTP请求 $this->bootstrap();【7、8】 // 进入管道模式,经过中间件,然后处理用户的请求【9、10】 return (new Pipeline($this->app)) ->send($request) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter());}

7. In thebootstrapmethod, run the given bootstrap class array$bootstrappers, loading configuration files, environment variables, service providers, facades, exception handling, boot providers, a very important step, located atvendor/laravel/framework/src/Illuminate/Foundation/ Http/Kernel.php

/** * Bootstrap the application for HTTP requests. * * @return void */public function bootstrap(){ if (! $this->app->hasBeenBootstrapped()) { $this->app->bootstrapWith($this->bootstrappers()); }}
/** * 运行给定的引导类数组 * * @param string[] $bootstrappers * @return void */public function bootstrapWith(array $bootstrappers){ $this->hasBeenBootstrapped = true; foreach ($bootstrappers as $bootstrapper) { $this['events']->dispatch('bootstrapping: '.$bootstrapper, [$this]); $this->make($bootstrapper)->bootstrap($this); $this['events']->dispatch('bootstrapped: '.$bootstrapper, [$this]); }}/** * Get the bootstrap classes for the application. * * @return array */protected function bootstrappers(){ return $this->bootstrappers;}/** * 应用程序的引导类 * * @var array */protected $bootstrappers = [ // 加载环境变量 \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class, // 加载config配置文件【重点】 \Illuminate\Foundation\Bootstrap\LoadConfiguration::class, // 加载异常处理 \Illuminate\Foundation\Bootstrap\HandleExceptions::class, // 加载门面注册 \Illuminate\Foundation\Bootstrap\RegisterFacades::class, // 加载在config/app.php中的providers数组里所定义的服务【8 重点】 \Illuminate\Foundation\Bootstrap\RegisterProviders::class, // 记载引导提供者 \Illuminate\Foundation\Bootstrap\BootProviders::class,];

8. Load the services

Illuminate\Auth\AuthServiceProvider::class,Illuminate\Broadcasting\BroadcastServiceProvider::class,....../** * 自己添加的服务提供者 */\App\Providers\HelperServiceProvider::class,
defined in theprovidersarray in

config/app.php

It can be seen that the commonly usedRedis, session, queue, auth, database, Routeand other services are loaded here

9. Use pipeline mode to process user requests, first go through Middleware processes and filters

return (new Pipeline($this->app)) ->send($request) // 如果没有为程序禁用中间件,则加载中间件(位置在app/Http/Kernel.php的$middleware属性) ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware) ->then($this->dispatchToRouter());}

app/Http/Kernel.php

/** * 应用程序的全局HTTP中间件 * * These middleware are run during every request to your application. * * @var array */protected $middleware = [ \App\Http\Middleware\TrustProxies::class, \App\Http\Middleware\CheckForMaintenanceMode::class, \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,];

10. After middleware processing, request distribution (including finding matching routes)

/** * 10.1 通过中间件/路由器发送给定的请求 * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ protected function sendRequestThroughRouter($request){ ... return (new Pipeline($this->app)) ... // 进行请求分发 ->then($this->dispatchToRouter());}
/** * 10.2 获取路由调度程序回调 * * @return \Closure */protected function dispatchToRouter(){ return function ($request) { $this->app->instance('request', $request); // 将请求发送到应用程序 return $this->router->dispatch($request); };}
/** * 10.3 将请求发送到应用程序 * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse */ public function dispatch(Request $request){ $this->currentRequest = $request; return $this->dispatchToRoute($request);}
/** * 10.4 将请求分派到路由并返回响应【重点在runRoute方法】 * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse */public function dispatchToRoute(Request $request){ return $this->runRoute($request, $this->findRoute($request));}
/** * 10.5 查找与给定请求匹配的路由 * * @param \Illuminate\Http\Request $request * @return \Illuminate\Routing\Route */protected function findRoute($request){ $this->current = $route = $this->routes->match($request); $this->container->instance(Route::class, $route); return $route;}
/** * 10.6 查找与给定请求匹配的第一条路由 * * @param \Illuminate\Http\Request $request * @return \Illuminate\Routing\Route * * @throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException */public function match(Request $request){ // 获取用户的请求类型(get、post、delete、put),然后根据请求类型选择对应的路由 $routes = $this->get($request->getMethod()); // 匹配路由 $route = $this->matchAgainstRoutes($routes, $request); if (! is_null($route)) { return $route->bind($request); } $others = $this->checkForAlternateVerbs($request); if (count($others) > 0) { return $this->getRouteForMethods($request, $others); } throw new NotFoundHttpException;}

Up to now, the route matching the request has been found, and it will be run later, which is the runRoute method in 10.4

/** * 10.7 返回给定路线的响应 * * @param \Illuminate\Http\Request $request * @param \Illuminate\Routing\Route $route * @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse */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) );}
/** * Run the given route within a Stack "onion" instance. * 10.8 在栈中运行路由,先检查有没有控制器中间件,如果有先运行控制器中间件 * * @param \Illuminate\Routing\Route $route * @param \Illuminate\Http\Request $request * @return mixed */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() ); });}
/** * Run the route action and return the response. * 10.9 最后一步,运行控制器的方法,处理数据 * @return mixed */ public function run() { $this->container = $this->container ?: new Container; try { if ($this->isControllerAction()) { return $this->runController(); } return $this->runCallable(); } catch (HttpResponseException $e) { return $e->getResponse(); } }

11. Run the route and return the response (emphasis)
You can see , one method in 10.7 isprepareResponse, which creates a response instance from a given value, and therunRouteWithinStackmethod runs the route in the stack, that is,Both httprequests and responses will be completed here.

Summary

So far, the entireLaravelframework’s running process has been analyzed, and the mystery of theLaravelframework has been revealed Veil, for the sake of the readability of the article, only the core code is given. You need to read the source code by yourself in conjunction with the article. It should be noted that you must understand the preparatory knowledge mentioned in the article. This is the premise and foundation for reading the source code of the framework. I hope you all learned something and get out of the car! ! !

The above is the detailed content of This article will help you thoroughly understand how Laravel works!. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:learnku.com. If there is any infringement, please contact admin@php.cn delete