热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Laravel实例化应用解析

实例化应用解析文件位于varwwwlaravelbootstrapapp.php,返回一个$app实例化应用(参数为项目根目录)$appnewIlluminate\Foundati

实例化应用解析

文件位于/var/www/laravel/bootstrap/app.php,返回一个$app

实例化应用(参数为项目根目录)


$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
public function __construct($basePath = null)
{
if ($basePath) {
// 设置基础路径
$this->setBasePath($basePath);
}
// 基础绑定
$this->registerBaseBindings();
// 注册基础服务
$this->registerBaseServiceProviders();
// 核心容器别名设置
$this->registerCoreContainerAliases();
}

1.1 设置基础路径

public function setBasePath($basePath)
{
$this->basePath = rtrim($basePath, '\/');
$this->bindPathsInContainer();
return $this;
}
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());
}
public function instance($abstract, $instance)
{
// 移除 abstractAliases
$this->removeAbstractAlias($abstract);
// 移除 aliases
unset($this->aliases[$abstract]);
// 直接设置容器属性 $this->instances
$this->instances[$abstract] = $instance;
// 当重新绑定时,进行重新构建
if ($this->bound($abstract)) {
$this->rebound($abstract);
}
}
protected function removeAbstractAlias($searched)
{
if (! isset($this->aliases[$searched])) {
return;
}
foreach ($this->abstractAliases as $abstract => $aliases) {
foreach ($aliases as $index => $alias) {
if ($alias == $searched) {
unset($this->abstractAliases[$abstract][$index]);
}
}
}
}

数组 $this->instances 如下:

$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 基础绑定


protected function registerBaseBindings()
{
static::setInstance($this); // 设置静态访问方式
$this->instance('app', $this);
$this->instance(Container::class, $this);
}

同样追加 $this->instances 如下:

$this->instances['app'] = object(Illuminate\Foundation\Application);
$this->instances['Illuminate\Container\Container'] = object(Illuminate\Foundation\Application);

1.3 注册基础服务

protected function registerBaseServiceProviders()
{
$this->register(new EventServiceProvider($this));
$this->register(new LogServiceProvider($this));
$this->register(new RoutingServiceProvider($this));
}
public function register($provider, $optiOns= [], $force = false)
{
// 已注册,则直接返回
if (($registered = $this->getProvider($provider)) && ! $force) {
return $registered;
}
// 若传的是字符串,则直接创建对象
if (is_string($provider)) {
$provider = $this->resolveProvider($provider);
}
// 服务提供者里若存在register方法,则直接自动调用
if (method_exists($provider, 'register')) {
$provider->register();
}
$this->markAsRegistered($provider);
// 当应用已经完全boot时,自动执行服务提供者里面的boot方法
if ($this->booted) {
$this->bootProvider($provider);
}
return $provider;
}
public function getProvider($provider)
{
$name = is_string($provider) ? $provider : get_class($provider);
// 从$this->serviceProviders中取出第一个符合closure的值
return Arr::first($this->serviceProviders, function ($value) use ($name) {
return $value instanceof $name; // $value是否$name的对象
});
}
protected function markAsRegistered($provider)
{
$this->serviceProviders[] = $provider;
$this->loadedProviders[get_class($provider)] = true;
}
protected function bootProvider(ServiceProvider $provider)
{
// 存在则调用相应服务提供者的boot方法
if (method_exists($provider, 'boot')) {
return $this->call([$provider, 'boot']);
}
}

一般情况下,服务提供者都会提供两个方法:register和boot(register先负责注册服务,boot则负责
随后的引导工作,此时可以调用前面已经注册的服务)。在注册服务提供者的时候,会相应的调用服务提供
者的register方法,然后再进行boot方法的调用。

生成数组如下:


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',
];

注意:

在register方法中,您只能将事物绑定到 服务容器 。不应该在register方法中尝试注册任何事件监听
器,路由或者任何其他功能。否则,您可能会意外的使用到尚未加载的服务提供者提供的服务。

1.4 核心容器别名设置

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

生成数组如下:

$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';
……

注册单例 Laravel 服务容器解析


$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
);
public function singleton($abstract, $cOncrete= null)
{
//
$this->bind($abstract, $concrete, true);
}

生成数组如下


$this->bindings['Illuminate\Contracts\Http\Kernel'] = [
'concrete' => function ($container, $parameters = []) {
return $container->make('App\Http\Kernel', $parameters);
},
'shared' => 'true',
];
$this->bindings['Illuminate\Contracts\Console\Kernel'] = [
'concrete' => function ($container, $parameters = []) {
return $container->make('App\Console\Kernel', $parameters);
},
'shared' => 'true',
];
$this->bindings['Illuminate\Contracts\Debug\ExceptionHandler'] = [
'concrete' => function ($container, $parameters = []) {
return $container->make('App\Exceptions\Handler', $parameters);
},
'shared' => 'true',
];

总结:

  1. 应用实例化的流程如下

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

  2. 服务容器

    服务容器里面的服务绑定形式有bind、singleton、instance方式,singleton和bind的唯一差别是传入的share真假问题,通过share变量来确定singleton只实例化一次。而instance绑定的就是已经实例化的对象。when则是通过上下文来进行绑定的,每次都会进行绑定和实例化。服务容器里面的服务调用方式:make方法、resolve全局函数、自动注入,均可以通过容器服务来解决依赖关系。


推荐阅读
author-avatar
手机用户2602936275
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有