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

This article will help you thoroughly understand how Laravel works!

藏色散人
Release: 2020-12-23 09:12:13
forward
4747 people have browsed it

The following is an introduction to the operating principle of Laravel from the Laravel Framework tutorial 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. The Laravel framework is a very excellent PHP framework. 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

Laravel Entry file of the frameworkindex.php

1. Introduce automatic loading autoload.php file

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

基本绑定($this、容器类Container等等)、

基本服务提供者的注册(Event、log、routing)、

核心类别名的注册(比如db、auth、config、router等)
Copy after login

3. StartHttp Request 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 方法,将请求分配到实际的控制器中,执行闭包或者方法,并得到响应结果
Copy after login

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';
Copy after login

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

$app = require_once __DIR__.'/../bootstrap/app.php';
Copy after login

app.php The file is as follows:

<?php
// 创建Laravel实例 【3】
$app = new Illuminate\Foundation\Application(
 $_ENV[&#39;APP_BASE_PATH&#39;] ?? dirname(__DIR__)
);
// 绑定Web端kernel
$app->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;
Copy after login

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(&#39;app&#39;, $this);
        $this->instance(Container::class, $this);
        $this->singleton(Mix::class);
        $this->instance(PackageManifest::class, new PackageManifest(
            new Filesystem, $this->basePath(), $this->getCachedPackagesPath()
        ));
        # 注:instance方法为将...注册为共享实例,singleton方法为将...注册为共享绑定
    }
Copy after login

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));
    }
Copy after login

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 of http

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

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__.&#39;/../bootstrap/app.php&#39;;这里面进行绑定的,实际指向的就是App\Http\Kernel::class这个类
Copy after login

5.2. Here the http request is processed

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

Enter$kernel In the represented class App\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 class use 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[&#39;events&#39;]->dispatch(
        new Events\RequestHandled($request, $response)
    );
    return $response;}
Copy after login

6. Process Http request ( Bind request to 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(&#39;request&#39;, $request);
    // 将请求request从已解析的门面实例中清除(因为已经绑定到共享实例中了,没必要再浪费资源了)
    Facade::clearResolvedInstance(&#39;request&#39;);
    // 引导应用程序进行HTTP请求
    $this->bootstrap();【7、8】    // 进入管道模式,经过中间件,然后处理用户的请求【9、10】
    return (new Pipeline($this->app))
                ->send($request)
                ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                ->then($this->dispatchToRouter());}
Copy after login

7. In the bootstrap method, run the given bootstrap class array$bootstrappers, loading configuration files, environment variables, service providers, facades, exception handling, boot providers, a very important step, located at vendor/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());
    }}
Copy after login
/**
 * 运行给定的引导类数组
 *
 * @param  string[]  $bootstrappers
 * @return void
 */public function bootstrapWith(array $bootstrappers){
    $this->hasBeenBootstrapped = true;
    foreach ($bootstrappers as $bootstrapper) {
        $this[&#39;events&#39;]->dispatch(&#39;bootstrapping: &#39;.$bootstrapper, [$this]);
        $this->make($bootstrapper)->bootstrap($this);
        $this[&#39;events&#39;]->dispatch(&#39;bootstrapped: &#39;.$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,];
Copy after login

8. Load the services <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">Illuminate\Auth\AuthServiceProvider::class,Illuminate\Broadcasting\BroadcastServiceProvider::class,....../** * 自己添加的服务提供者 */\App\Providers\HelperServiceProvider::class,</pre><div class="contentsignin">Copy after login</div></div> defined in the providers array in

config/app.php

It can be seen that the commonly used Redis, session, queue, auth, database, Route and 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());}
Copy after login

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,];
Copy after login

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());}
Copy after login
/**
 * 10.2 获取路由调度程序回调
 *
 * @return \Closure
 */protected function dispatchToRouter(){
    return function ($request) {
        $this->app->instance(&#39;request&#39;, $request);
        // 将请求发送到应用程序
        return $this->router->dispatch($request);
    };}
Copy after login
/**
 * 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);}
Copy after login
 /**
 * 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));}
Copy after login
/**
 * 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;}
Copy after login
/**
 * 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;}
Copy after login

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)
    );}
Copy after login
/**
 * 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(&#39;middleware.disable&#39;) &&
                            $this->container->make(&#39;middleware.disable&#39;) === 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()
            );
        });}
Copy after login
 /**
     * 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();
        }
    }
Copy after login

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

Summary

So far, the entire Laravel framework’s running process has been analyzed, and the mystery of the Laravel framework 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!

Related labels:
source:learnku.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template