阅读本文前,建议先阅读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
18define('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
52public 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 | // 通过前面在$app中注册的Illuminate\Contracts\Http\Kernel::class,现在获取Http实例 |
终于,laravel的启动讲完了。能看到这里说明你是一个有决心看源码的读者!加油,前路依然不平坦…
参考:https://segmentfault.com/a/1190000008848349