Laravel 2.2 创建 Application 实例
简述
laravel 框架运行
1 第一步,使用 Composer 完成自动加载
2 第二步
- 创建Application实例,
- 注册项目路径(如config、public)、
- 注册项目基础服务(如app实例、Container实例、第三方插件)、
- 注册项目服务提供者(Event、Log、Routing等)、
- 注册项目服务提供者别名(auth等)
Illuminate\Foundation\Application
是框架最核心的类,管理整个框架的启动、运行以及整个生命周期,并通过 ServiceProvider 将其他功能的模块载入框架。Application 是 Container 类的子类,所以也管理者框架中其他类的实例化、存储等功能。
<?php
// 第一部分: 创建应用实例
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
// 第二部分: 完成内核绑定
$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 容器 、注册基础服务提供者至 APP 容器 、注册核心容器别名至 APP 容器 等基础服务的注册工作
* Create a new Illuminate application instance.
*
* @param string|null $basePath
* @return void
*/
public function __construct($basePath = null)
{
//设置应用程序的绝对路径
if ($basePath) {
$this->setBasePath($basePath);
}
//绑定 Application 对象、绑定 Container 对象,绑定 需要加载的第三方的插件
$this->registerBaseBindings();
//在容器中注册最基本的服务提供者(即ServiceProvider)
$this->registerBaseServiceProviders();
//在容器中注册核心类别名
$this->registerCoreContainerAliases();
}
setBasePath
- 设置应用程序的绝对路径
- 依赖于初始化时传入的路径参数,路径为项目的根目录。在 setBasePath 方法中,bindPathsInContainer 方法被调用。这里又用到了 instance 方法,把路径填入了类的 $instances 数组中。
$this->instance
是Illuminate\Container
的成员方法,instance 函数的作用是绑定一个已有对象到容器中,这个对象在容器中共享并且可以通 过键获取。
/**
* 设置应用程序的绝对路径..
*
* @param string $basePath 代码里面传的是 realpath(__DIR__.'/../'),就是根目录
* @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());
}
registerBaseBindings
这里同样调用了 instance 方法,但与之前不同的是,这里传入的第二个参数是一个类,而之前的是一个字符串。第一行它为 Application 类注册了一个名为 $instance 的静态实例,二三两行则为 Application 实例中的 $instances 数组属性填入了两个 key 为 'app' 和 Container::class,value 为 $this 的值。
前两个主要是绑定 Application
对象和 Container
对象。重点分析 PackageManifest
对象之前,我们看看 $this->getCachedPackagesPath()
这个函数:
/**
* Register the basic bindings into the container.
* 将 bindings 注册到容器中
* @return void
*/
protected function registerBaseBindings()
{
//将 $this 赋值给自身的 instance 静态变 量
static::setInstance($this);
//绑定 Application 对象
//注册一个实例到容器中,这个就变成了 $this->instances['app']=application实例
//你可以使用App::make('app')来取得一个容器对象
$this->instance('app', $this);
//绑定 Container 对象
//注册一个实例到容器中, $this->instances['"Illuminate\Container\Container"]=Application 实例
$this->instance(Container::class, $this);
//绑定 需要加载的第三方的插件
$this->instance(PackageManifest::class, new PackageManifest(
new Filesystem, $this->basePath(), $this->getCachedPackagesPath()
));
}
getCachedPackagesPath
这个就是 bootstrap/cache/packages.php
文件路径
/**
* Get the path to the cached packages.php file.
* 这个就是 bootstrap/cache/packages.php文件
* @return string
*/
public function getCachedPackagesPath()
{
return $this->bootstrapPath().'/cache/packages.php';
}
- 通过分析,可以看出这个文件主要是放着我们自己引入第三方的
ServiceProviders
和aliases
,我们对照项目根路径的composer.json
你就可以证实了:
bootstrap/cache/packages.php
文件
<?php return array (
'fideloper/proxy' =>
array (
'providers' =>
array (
0 => 'Fideloper\\Proxy\\TrustedProxyServiceProvider',
),
),
'encore/laravel-admin' =>
array (
'providers' =>
array (
0 => 'Encore\\Admin\\AdminServiceProvider',
),
'aliases' =>
array (
'Admin' => 'Encore\\Admin\\Facades\\Admin',
),
),
'laravel/tinker' =>
array (
'providers' =>
array (
0 => 'Laravel\\Tinker\\TinkerServiceProvider',
),
),
'rebing/graphql-laravel' =>
array (
'providers' =>
array (
0 => 'Rebing\\GraphQL\\GraphQLServiceProvider',
),
'aliases' =>
array (
'GraphQL' => 'Rebing\\GraphQL\\Support\\Facades\\GraphQL',
),
),
'tymon/jwt-auth' =>
array (
'aliases' =>
array (
'JWTAuth' => 'Tymon\\JWTAuth\\Facades\\JWTAuth',
'JWTFactory' => 'Tymon\\JWTAuth\\Facades\\JWTFactory',
),
'providers' =>
array (
0 => 'Tymon\\JWTAuth\\Providers\\LaravelServiceProvider',
),
),
'noh4ck/graphiql' =>
array (
'providers' =>
array (
0 => 'Graphiql\\GraphiqlServiceProvider',
),
),
'rollbar/rollbar-laravel' =>
array (
'providers' =>
array (
0 => 'Rollbar\\Laravel\\RollbarServiceProvider',
),
'aliases' =>
array (
'Rollbar' => 'Rollbar\\Laravel\\Facades\\Rollbar',
),
),
'fanly/log2dingding' =>
array (
'providers' =>
array (
0 => 'Fanly\\Log2dingding\\FanlyLog2dingdingServiceProvider',
),
),
);
项目根路径的 composer.json
文件
"require": {
"php": ">=7.0.0",
"encore/laravel-admin": "1.5.*",
"fanly/log2dingding": "^0.0.2",
"fideloper/proxy": "~3.3",
"guzzlehttp/guzzle": "^6.3",
"laravel/framework": "5.5.*",
"laravel/tinker": "~1.0",
"noh4ck/graphiql": "@dev",
"overtrue/phplint": "^1.1",
"rebing/graphql-laravel": "^1.10",
"rollbar/rollbar-laravel": "^2.3",
"tymon/jwt-auth": "^1.0@dev"
},
new PackageManifest()
回过头来分析 new PackageManifest()
/**
* 这个函数是将 package.php 文件的插件数组的 `providers`整合成一个 Collection 输出,什么是 Collection ,看之前的文章 Laravel Collections
*/
public function providers() {}
/**
* 插件中的 `aliases` 整合成 Collection 输出。
*
* @return array
*/
public function aliases() {}
/**
* 这个是关键,从 verdor/composer/installed.json 文件中获取所有通过 composer 安装的插件数组,然后再通过用 `name` 绑定对应的 `ServiceProvider`,构成数组,然后再排除每个插件的 `dont-discover` 和项目 composer.json 填入的 `dont-discover`。
* 这也是 Laravel 包自动发现的核心所在。
*
*/
public function build()
{
$packages = [];
if ($this->files->exists($path = $this->vendorPath.'/composer/installed.json')) {
$packages = json_decode($this->files->get($path), true);
}
$ignoreAll = in_array('*', $ignore = $this->packagesToIgnore());
$this->write(collect($packages)->mapWithKeys(function ($package) {
return [$this->format($package['name']) => $package['extra']['laravel'] ?? []];
})->each(function ($configuration) use (&$ignore) {
$ignore = array_merge($ignore, $configuration['dont-discover'] ?? []);
})->reject(function ($configuration, $package) use ($ignore, $ignoreAll) {
return $ignoreAll || in_array($package, $ignore);
})->filter()->all());
}
/**
* 最后就把上面的满足的 ServiceProvider 写入到文件中,就是上文我们说的 `bootstrap/cache/packages.php`
*/
protected function write(array $manifest) {}
registerBaseServiceProviders
这里主要注册三个 ServiceProvider
,在注册过程中,ServiceProvider 的 register 方法会被执行,每一个 ServiceProvider 一般都会有 register 方法。
/**
* Register all of the base service providers.
*
* @return void
*/
protected function registerBaseServiceProviders()
{
//EventServieProvider —— 事件服务提供者
//EventServiceProvider这个服务提供者,其实是向容器注册了一个key为events的对象
$this->register(new EventServiceProvider($this));
//日志服务
$this->register(new LogServiceProvider($this));
//RoutingServiceProvider —— 路由服务提供者
//路由服务,这个里面注册了很多东西,从下图可以看出来,路由以后单独分析
$this->register(new RoutingServiceProvider($this));
//最后他们的实例都在 $this->bindings 里面, 如下图
}
registerCoreContainerAliases
这一步是在为一些核心类注册别名,这些数据就会一个有规律,数组都是接口和这个接口实例,这也就是laravel 里的contracts
在调用此方法之前,我们想取得一个容器实例的做法是 App::make('app')
,现在我们可以使用App::make('Illuminate\Foundation\Application')
App::make('Illuminate\Contracts\Container\Container')
App::make('Illuminate\Contracts\Foundation\Application')
三种方法来取得一个容器实例,即Illuminate\Foundation\Application
、Illuminate\Contracts\Container\Container
、Illuminate\Contracts\Foundation\Application
三者都是app的别名;
/**
* Register the core class aliases in the container.
* 在容器中注册核心类别名
* @return void
*/
public function registerCoreContainerAliases()
{
foreach ([
'app' => [\Illuminate\Foundation\Application::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::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],
] as $key => $aliases) {
foreach ($aliases as $alias) {
$this->alias($key, $alias);
}
}
}
Application 实例
最后返回了一个Application 实例
本作品采用《CC 协议》,转载必须注明作者和本文链接