Laravel框架的运行过程

Laravel框架的入口文件public/index.php

<?php

/**
 * Laravel - A PHP Framework For Web Artisans
 *
 * @package  Laravel
 * @author   Taylor Otwell <taylor@laravel.com>
 */

define('LARAVEL_START', microtime(true));

/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader for
| our application. We just need to utilize it! We'll simply require it
| into the script here so that we don't have to worry about manual
| loading any of our classes later on. It feels great to relax.
|
*/

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

/*
|--------------------------------------------------------------------------
| Turn On The Lights
|--------------------------------------------------------------------------
|
| We need to illuminate PHP development, so let us turn on the lights.
| This bootstraps the framework and gets it ready for use, then it
| will load up this application so that we can run it and send
| the responses back to the browser and delight our users.
|
*/

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

/*
|--------------------------------------------------------------------------
| Run The Application
|--------------------------------------------------------------------------
|
| Once we have the application, we can handle the incoming request
| through the kernel, and send the associated response back to
| the client's browser allowing them to enjoy the creative
| and wonderful application we have prepared for them.
|
*/

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

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

$response->send();

$kernel->terminate($request, $response);

根据作者的注释可以知道这几行代码的作用:

  1. 定义常量记录框架启动时间。
  2. 加载composer包管理器中的自动加载器到当前命名空间(根命名空间)。
  3. 获取一个Application类的实例$app,这个实例继承了Container类,并且作为一个服务容器承担连接各种服务的功能,我们可以从这个容器获取各种服务,如日志、数据库、缓存、事件等。
  4. 调用$app的make方法获取一个kernel类,用kernel类处理请求对象(Request类的实例,包含了请求信息),之后返回一个$response来发送响应,最后调用$kernel的terminate方法结束本次请求,这样,一个完整的http请求就完成了。

        框架的启动过程在kernel调用handle方法时进行,那么启动框架到底做了什么事情?这就要深入了解下kernel类的handle方法了。
找到kernel类文件中的handle 方法:

/**
     * Handle an incoming HTTP request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function handle($request)
    {
        try {
            $request->enableHttpMethodParameterOverride();

            $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;
    }

         这个方法接受一个\Illuminate\Http\Request请求类实例作为参数,然后返回一个\Illuminate\Http\Response响应类。正常请求会调用sendRequestThroughRouter方法,翻过过来就是:“将请求送往路由”,然后返回响应,如果产生异常则调用异常处理方法,将异常信息包装为响应类。接下来看下sendRequestThroughRouter方法:

/**
     * Send the given request through the middleware / router.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    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());
    }

这个方法并不长,只有四行代码:

  1. 调用服务容器的instance方法绑定一个request实例
  2. 调用Illuminate\Support\Facades\Facade类(门面类基类)的clearResolvedInstance静态方法清除resolvedInstance属性(已解析实例)中的’request’实体。
  3. 调用bootstrap方法启动框架。
  4. new一个管道类,依次调用send、through、then方法使请求通过中间件,最后分发到路由类处理。

 看到这里,就知道框架的启动过程放在了bootstrap方法,继续看下这个方法:

/**
     * Bootstrap the application for HTTP requests.
     *
     * @return void
     */
    public function bootstrap()
    {
        if (! $this->app->hasBeenBootstrapped()) {
            $this->app->bootstrapWith($this->bootstrappers());
        }
    }

        判断框架是否启动,未启动则调用服务容器的bootstrapWith方法,传入了kernel的bootstrappers 属性,这个属性是一个数组,数组的键值是类名,这些是在框架启动之时需要注入的类,如管理环境变量、框架配置的类,处理异常类,注册门面类,启动服务类。

protected $bootstrappers = [
        \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
        \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
        \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
        \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
        \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
        \Illuminate\Foundation\Bootstrap\BootProviders::class,
    ];

继续看下服务容器的bootstrapWith方法:

/**
     * Run the given array of bootstrap classes.
     *
     * @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]);
        }
    }

        在这个方法中只有几行代码,将启动属性修改为已启动,然后遍历bootstrappers 数组,启动框架的过程就是一个加载基础类的过程:发布启动事件,调用make方法实例化基础类然后调用基础类的bootstrap方法,然后发布完成启动事件。bootstrappers 数组中的类都定义在laravel源码包 的Foundation目录的子目录Bootstrap中。这些类的功能:

  1. 加载环境变量
  2. 加载配置文件
  3. 加载异常处理类
  4. 注册门面类
  5. 注册服务提供类
  6. 启动服务类

        以上就是laravel框架的启动全过程,我们在框架启动之后,还未处理请求之前调用一下框架的辅助函数dd()和app()来打印下服务容器对象: 

protected function sendRequestThroughRouter($request)
    {
        $this->app->instance('request', $request);

        Facade::clearResolvedInstance('request');

        $this->bootstrap();
dd(app());
        return (new Pipeline($this->app))
                    ->send($request)
                    ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                    ->then($this->dispatchToRouter());
    }

打印结果:

Application {#2 ▼
  #basePath: "/vagrant/www/laravel5.8"
  #hasBeenBootstrapped: true
  #booted: true
  #bootingCallbacks: array:1 [▶]
  #bootedCallbacks: array:1 [▶]
  #terminatingCallbacks: []
  #serviceProviders: array:22 [▶]
  #loadedProviders: array:22 [▶]
  #deferredServices: array:102 [▶]
  #appPath: null
  #databasePath: null
  #storagePath: null
  #environmentPath: null
  #environmentFile: ".env"
  #namespace: null
  #resolved: array:20 [▶]
  #bindings: array:41 [▶]
  #methodBindings: []
  #instances: array:26 [▼
    "path" => "/vagrant/www/laravel5.8/app"
    "path.base" => "/vagrant/www/laravel5.8"
    "path.lang" => "/vagrant/www/laravel5.8/resources/lang"
    "path.config" => "/vagrant/www/laravel5.8/config"
    "path.public" => "/vagrant/www/laravel5.8/public"
    "path.storage" => "/vagrant/www/laravel5.8/storage"
    "path.database" => "/vagrant/www/laravel5.8/database"
    "path.resources" => "/vagrant/www/laravel5.8/resources"
    "path.bootstrap" => "/vagrant/www/laravel5.8/bootstrap"
    "app" => Application {#2}
    "Illuminate\Container\Container" => Application {#2}
    "Illuminate\Foundation\PackageManifest" => PackageManifest {#5 ▶}
    "events" => Dispatcher {#27 ▶}
    "router" => Router {#26 ▶}
    "Illuminate\Contracts\Http\Kernel" => Kernel {#30 ▶}
    "request" => Request {#43 ▶}
    "config" => Repository {#34 ▶}
    "db.factory" => ConnectionFactory {#53 ▶}
    "db" => DatabaseManager {#37 ▶}
    "view.engine.resolver" => EngineResolver {#105 ▶}
    "files" => Filesystem {#111}
    "view" => Factory {#112 ▶}
    "translation.loader" => FileLoader {#119 ▶}
    "translator" => Translator {#120 ▶}
    "routes" => RouteCollection {#29 ▶}
    "url" => UrlGenerator {#128 ▶}
  ]
  #aliases: array:66 [▶]
  #abstractAliases: array:36 [▶]
  #extenders: []
  #tags: []
  #buildStack: []
  #with: []
  +contextual: array:1 [▶]
  #reboundCallbacks: array:2 [▶]
  #globalResolvingCallbacks: []
  #globalAfterResolvingCallbacks: []
  #resolvingCallbacks: array:1 [▶]
  #afterResolvingCallbacks: array:1 [▶]
}

        可以看到在处理请求之前,服务容器中的instances共享实例属性,就已经注册了十几个对象,而在处理请求的过程中又还要注册很多对象,这也就不难理解为什么laravel框架的并发性较差了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值