laravel框架启动过程

阅读本文前,建议先阅读laravel生命周期

核心文件

了解laravel的读者都知道,public目录是laravel项目的入口,所以,laravel框架的整个启动流程就定义在public/index.php文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
define('LARAVEL_START', microtime(true));

// 注册自动加载器
require __DIR__.'/../vendor/autoload.php';

// 实例化应用
$app = require_once __DIR__.'/../bootstrap/app.php';

// 处理请求和响应
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

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

$response->send();

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

上面短短几行代码是如何将laravel框架运行起来的呢?请看下面具体分析

注册自动加载器

启动一个框架,自然少不了在文件中加载大量的类,而laravel实现类的加载是十分轻松的!

1
2
3
4
5
// 记录项目启动的时刻
define('LARAVEL_START', microtime(true));

// 注册类自动加载器
require __DIR__.'/../vendor/autoload.php';

autoload.php是由composer提供的类自动加载器文件,包含它即可以实现自动加载框架类。

实例化应用

包含了类文件后,接下来,就是实例化laravel应用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$app = require_once __DIR__.'/../bootstrap/app.php';
```
通过上述一条语句实现了laravel application的实例化,下面分析下`$app`实例化的具体过程:
``` php
// bootstrap/app.php文件
// 实例化$app
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);

// 单例绑定共享的Kernel和异常处理器
$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);

$app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
);

$app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);

return $app;

  • 实例化$app

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    /**
    * Create a new Illuminate application instance.
    *
    * @param string|null $basePath
    * @return void
    */
    public function __construct($basePath = null)
    {
    // 设置基础路径
    if ($basePath) {
    $this->setBasePath($basePath);
    }

    // 注册基础绑定
    $this->registerBaseBindings();

    // 注册基础服务
    $this->registerBaseServiceProviders();

    // 注册核心容器别名
    $this->registerCoreContainerAliases();
    }
    • 设置基础路径
      在容器中设置app、/、config、public、storage、database等目录的路径

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      /**
      * Set the base path for the application.
      *
      * @param string $basePath
      * @return $this
      */
      public function setBasePath($basePath)
      {
      $this->basePath = rtrim($basePath, '\/');

      $this->bindPathsInContainer();

      return $this;
      }

      /**
      * Bind all of the application paths in the container.
      *
      * @return void
      */
      protected function bindPathsInContainer()
      {
      $this->instance('path', $this->path());
      $this->instance('path.base', $this->basePath());
      $this->instance('path.lang', $this->langPath());
      $this->instance('path.config', $this->configPath());
      $this->instance('path.public', $this->publicPath());
      $this->instance('path.storage', $this->storagePath());
      $this->instance('path.database', $this->databasePath());
      $this->instance('path.resources', $this->resourcePath());
      $this->instance('path.bootstrap', $this->bootstrapPath());
      }

      绑定后的数组 $this->instances 如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      $this->instances['path'] = '/var/www/laravel/app';  
      $this->instances['path.base'] = '/var/www/laravel';
      $this->instances['path.lang'] = '/var/www/laravel/resources/lang';
      $this->instances['path.config'] = '/var/www/laravel/config';
      $this->instances['path.public'] = '/var/www/laravel/public';
      $this->instances['path.storage'] = '/var/www/laravel/storage';
      $this->instances['path.database'] = '/var/www/laravel/database';
      $this->instances['path.resources'] = '/var/www/laravel/resources';
      $this->instances['path.bootstrap'] = '/var/www/laravel/bootstrap';
    • 注册基础绑定

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      /**
      * 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->instance(PackageManifest::class, new PackageManifest(
      new Filesystem, $this->basePath(), $this->getCachedPackagesPath()
      ));
      }

      追加$this->instances 如下:

      1
      2
      3
      $this->instances['app'] = object(Illuminate\Foundation\Application);  
      $this->instances['Illuminate\Container\Container'] = object(Illuminate\Foundation\Application);
      $this->instances['PackageManifest'] = object(PackageManifest);
    • 注册基础服务
      注册事件、日志、路由服务

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      /**
      * Register all of the base service providers.
      *
      * @return void
      */
      protected function registerBaseServiceProviders()
      {
      $this->register(new EventServiceProvider($this));

      $this->register(new LogServiceProvider($this));

      $this->register(new RoutingServiceProvider($this));
      }

      生成数组如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
          
      event:
      $this->bindings['events'] = [
      'concrete' => function ($app) {
      return (new Dispatcher($app))->setQueueResolver(function () use ($app) {
      return $app->make(QueueFactoryContract::class);
      });
      }
      'shared' => 'true',
      ];
      log:
      $this->bindings['log'] = [
      'concrete' => function () {
      return function createLogger()
      {
      $log = new Writer(
      new Monolog($this->channel()), $this->app['events']
      );

      if ($this->app->hasMonologConfigurator()) {
      call_user_func($this->app->getMonologConfigurator(), $log->getMonolog());
      } else {
      $this->{$this->{'configure'.ucfirst($this->handler()).'Handler'}($log)}($log);
      }

      return $log;
      }
      }
      'shared' => 'true',
      ];
      router:
      $this->bindings['router'] = [
      'concrete' => function ($app) {
      return new Router($app['events'], $app);
      },
      'shared' => 'true',
      ];
      $this->bindings['url'] = [
      'concrete' => function ($app) {
      $routes = $app['router']->getRoutes();

      $app->instance('routes', $routes);

      $url = new UrlGenerator(
      $routes, $app->rebinding(
      'request', $this->requestRebinder()
      )
      );

      $url->setSessionResolver(function () {
      return $this->app['session'];
      });

      $app->rebinding('routes', function ($app, $routes) {
      $app['url']->setRoutes($routes);
      });

      return $url;
      },
      'shared' => 'true',
      ];
      $this->bindings['redirect'] = [
      'concrete' => function ($app) {
      $redirector = new Redirector($app['url']);

      if (isset($app['session.store'])) {
      $redirector->setSession($app['session.store']);
      }

      return $redirector;
      },
      'shared' => 'true',
      ];
      $this->bindings[ServerRequestInterface::class] = [
      'concrete' => function ($app) {
      return (new DiactorosFactory)->createRequest($app->make('request'));
      },
      'shared' => 'true',
      ];
      $this->bindings[ResponseInterface::class] = [
      'concrete' => function ($app) {
      return new PsrResponse();
      },
      'shared' => 'true',
      ];
      $this->bindings[ResponseFactoryContract::class] = [
      'concrete' => function ($app) {
      return new ResponseFactory($app[ViewFactoryContract::class], $app['redirect']);
      },
      'shared' => 'true',
      ];
    • 注册核心容器别名

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      public function registerCoreContainerAliases()
      {
      $aliases = [
      'app' => [\Illuminate\Foundation\Application::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class],
      'auth' => [\Illuminate\Auth\AuthManager::class, \Illuminate\Contracts\Auth\Factory::class],
      'auth.driver' => [\Illuminate\Contracts\Auth\Guard::class],
      'blade.compiler' => [\Illuminate\View\Compilers\BladeCompiler::class],
      'cache' => [\Illuminate\Cache\CacheManager::class, \Illuminate\Contracts\Cache\Factory::class],
      'cache.store' => [\Illuminate\Cache\Repository::class, \Illuminate\Contracts\Cache\Repository::class],
      'config' => [\Illuminate\Config\Repository::class, \Illuminate\Contracts\Config\Repository::class],
      'cookie' => [\Illuminate\Cookie\CookieJar::class, \Illuminate\Contracts\Cookie\Factory::class, \Illuminate\Contracts\Cookie\QueueingFactory::class],
      'encrypter' => [\Illuminate\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\Encrypter::class],
      'db' => [\Illuminate\Database\DatabaseManager::class],
      'db.connection' => [\Illuminate\Database\Connection::class, \Illuminate\Database\ConnectionInterface::class],
      'events' => [\Illuminate\Events\Dispatcher::class, \Illuminate\Contracts\Events\Dispatcher::class],
      'files' => [\Illuminate\Filesystem\Filesystem::class],
      'filesystem' => [\Illuminate\Filesystem\FilesystemManager::class, \Illuminate\Contracts\Filesystem\Factory::class],
      'filesystem.disk' => [\Illuminate\Contracts\Filesystem\Filesystem::class],
      'filesystem.cloud' => [\Illuminate\Contracts\Filesystem\Cloud::class],
      'hash' => [\Illuminate\Contracts\Hashing\Hasher::class],
      'translator' => [\Illuminate\Translation\Translator::class, \Illuminate\Contracts\Translation\Translator::class],
      'log' => [\Illuminate\Log\Writer::class, \Illuminate\Contracts\Logging\Log::class, \Psr\Log\LoggerInterface::class],
      'mailer' => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class],
      'auth.password' => [\Illuminate\Auth\Passwords\PasswordBrokerManager::class, \Illuminate\Contracts\Auth\PasswordBrokerFactory::class],
      'auth.password.broker' => [\Illuminate\Auth\Passwords\PasswordBroker::class, \Illuminate\Contracts\Auth\PasswordBroker::class],
      'queue' => [\Illuminate\Queue\QueueManager::class, \Illuminate\Contracts\Queue\Factory::class, \Illuminate\Contracts\Queue\Monitor::class],
      'queue.connection' => [\Illuminate\Contracts\Queue\Queue::class],
      'queue.failer' => [\Illuminate\Queue\Failed\FailedJobProviderInterface::class],
      'redirect' => [\Illuminate\Routing\Redirector::class],
      'redis' => [\Illuminate\Redis\RedisManager::class, \Illuminate\Contracts\Redis\Factory::class],
      'request' => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class],
      'router' => [\Illuminate\Routing\Router::class, \Illuminate\Contracts\Routing\Registrar::class, \Illuminate\Contracts\Routing\BindingRegistrar::class],
      'session' => [\Illuminate\Session\SessionManager::class],
      'session.store' => [\Illuminate\Session\Store::class, \Illuminate\Contracts\Session\Session::class],
      'url' => [\Illuminate\Routing\UrlGenerator::class, \Illuminate\Contracts\Routing\UrlGenerator::class],
      'validator' => [\Illuminate\Validation\Factory::class, \Illuminate\Contracts\Validation\Factory::class],
      'view' => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class],
      ];

      foreach ($aliases as $key => $aliases) {
      foreach ($aliases as $alias) {
      $this->alias($key, $alias);
      }
      }
      }

      public function alias($abstract, $alias)
      {
      $this->aliases[$alias] = $abstract;

      $this->abstractAliases[$abstract][] = $alias;
      }

      生成数组如下:

      1
      2
      3
      4
      5
      6
      7
      $this->aliases['Illuminate\Foundation\Application'] = 'app';
      $this->aliases['Illuminate\Contracts\Container\Container'] = 'app';
      $this->aliases['Illuminate\Contracts\Foundation\Application'] = 'app';
      $this->abstractAliases['app'][] = 'Illuminate\Foundation\Application';
      $this->abstractAliases['app'][] = 'Illuminate\Contracts\Container\Container';
      $this->abstractAliases['app'][] = 'Illuminate\Contracts\Foundation\Application';
      ……
  • 单例绑定共享的Kernel和异常处理器
    单例绑定Http、Console的Kernel和异常处理器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $app->singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
    );

    $app->singleton(
    Illuminate\Contracts\Console\Kernel::class,
    App\Console\Kernel::class
    );

    $app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
    );

总结:

1
2
3
4
5
设置基础路径($this->instances['path.*']) => 
注册基础绑定($this->instances['app|Container']) =>
注册基础服务($this->bindings[]) =>
注册核心容器别名($this->aliases[],$this->abstractAliases[])
至此,应用的实例化完成。

处理请求和响应

1
2
3
4
5
6
7
8
9
10
11
12
13
// 通过前面在$app中注册的Illuminate\Contracts\Http\Kernel::class,现在获取Http实例
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

// Kernel处理器调用handle方法处理当前请求,得到response
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);

// 发送响应信息到浏览器
$response->send();

// 请求结束,进行回调
$kernel->terminate($request, $response);

终于,laravel的启动讲完了。能看到这里说明你是一个有决心看源码的读者!加油,前路依然不平坦…
参考:https://segmentfault.com/a/1190000008848349

-------------本文结束  感谢您的阅读-------------