Skip to content

源码阅读 - 初始 : (2) 初始化 App

加载机制

公共文件入口

public/index.php

bootstrap/autoload.php
自动加载机制
    vendor/autoload.php
    加载 composer 扩展包的自动加载机制
    storage/framework/compiled.php
    如果存在编译文件则加载编译文件
bootstrap/app.php
	创建 `$app` = new Illuminate\Foundation\Application
		注册基础绑定 registerBaseBindings
			实例化 app
			实例化 Illuminate\Container\Container
		注册基础服务绑定	registerBaseServiceProviders
			注册 事件绑定
			注册 路由绑定
		注册核心容器 alias 关联	registerCoreContainerAliases
	App\Http\Kernel
	App\Console\Kernel
	App\Exceptions\Handler
kernel 的处理
- 创建 `kernel`
- 创建 `response`
- 发出 `response`
- 终止 `kernel`

初始化 Application

根据指定的路径来初始化应用, 原始码

php
$app = new Illuminate\Foundation\Application(
	realpath(__DIR__ . '/../')
);

Illuminate/Foundation/Application::__construct()

php
// 1) 注册基本绑定
$this->registerBaseBindings();
// 2) 注册服务提供者
// 如果存在 register 方法, 则执行并且标记为已经注册过. 如果系统已经启动, 则直接运行 boot 方法
$this->registerBaseServiceProviders();
// 3) 注册核心 Alias
$this->registerCoreContainerAliases();

1) 注册基本绑定

php
# 1) 实例化 app
$this->instance('app', $this);
# 实例化 container => app
$this->instance(Container::class, $this);
# 2) 实例化 PackageManifest
$this->instance(PackageManifest::class, new PackageManifest(...));

1-1) 实例化 app

实例化 App[Application::instance()]

这里拿 ('app', $this)为例子来阅读源码

php
// 移除抽象关联
$this->removeAbstractAlias($abstract);
// 确定给定的抽象类型是否已经绑定
// 已经设定 Alias
$isBound = $this->bound($abstract);
// 移除关联
unset($this->aliases[$abstract]);
// 检测此类型是否被绑定过, 如果已经绑定会重新触发绑定并且更新类
// 实例化 instances['app'] = $this
$this->instances[$abstract] = $instance;
// 重新绑定
if ($isBound) {
    $this->rebound($abstract);
    // 1) make -> alias (resolve)
    # $this->make($abstract)
    
    // 触发回调
    # foreach ($this->getReboundCallbacks($abstract) as $callback) {
    #     call_user_func($callback, $this, $instance);
    # }
}

1-2) 实例化 PackageManifest

2) 注册事件处理

php
// 注册事件处理器
$this->register(new EventServiceProvider($this));
// 注册日志服务
$this->register(new LogServiceProvider($this));
// 注册路由服务
$this->register(new RoutingServiceProvider($this));

2-1) Application::register() 方法

php
/* sample service providers
$this->serviceProviders = [
    Illuminate\Events\EventServiceProvider Object
    Illuminate\Log\LogServiceProvider Object
    Illuminate\Routing\RoutingServiceProvider Object
];
*/
// 获取注册的对象, 传递($provider) 可以是对象/字串
if (($registered = $this->getProvider($provider)) && ! $force) {
    return $registered;
}
// 如果给定的 provider 是字串, 则返回实例化的对象.
if (is_string($provider)) {
    $provider = $this->resolveProvider($provider);
    # new $provider($this)
}
// 检测给定的对象是否存在 register 方法, 存在则执行 register 方法并标注为已注册
if (method_exists($provider, 'register')) {
    $provider->register();
}
$this->markAsRegistered($provider);
// todo - 什么时候启动
// 如果应用已经启动, 我们便有机会启动 ServiceProvider 的 boot 逻辑, 便于开发者持续开发
if ($this->booted) {
    $this->bootProvider($provider);
    # 启动 boot 方法
    # if (method_exists($provider, 'boot')) {
    #     return $this->call([$provider, 'boot']);
    # }
}
return $provider;

2-2) EventServiceProvider

// 注册事件触发器, 并且配置队列执行
$this->app->singleton('events', function ($app) {
    return (new Dispatcher($app))->setQueueResolver(function () use ($app) {
        return $app->make(QueueFactoryContract::class);
    });
});

2-3) LogServiceProvider

// 注册日志
$this->app->singleton('log', function () {
    return $this->createLogger();
});

2-4) RoutingServiceProvider

// 注册路由
$this->registerRouter();
// url 生成
$this->registerUrlGenerator();
// 定向器
$this->registerRedirector();
// psr 请求
$this->registerPsrRequest();
// psr 响应
$this->registerPsrResponse();
// 响应工厂
$this->registerResponseFactory();
// 控制器触发器
$this->registerControllerDispatcher();

3) 注册 Alias

将指定的类和 app 示例做绑定

php
$allAlias = [
    'app'                  => [
    	\Illuminate\Foundation\Application::class, 
    	\Illuminate\Contracts\Container\Container::class, 
    	\Illuminate\Contracts\Foundation\Application::class,  
    	\Psr\Container\ContainerInterface::class
    ],
    ...
    'view'                 => [
    	\Illuminate\View\Factory::class, 
    	\Illuminate\Contracts\View\Factory::class
    ],
];
        
foreach($allAlias = as $key => $aliases) {
    foreach ($aliases as $alias) {
        // key   : app
        // alias : Illuminate\Foundation\Application::class
        $this->alias($key, $alias);
    }
}

3-1) 系统 alias 项目

php
$alias = [
    '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
    ],
];

3-2) alias 结果

php
/* $this->aliases = [
    [Illuminate\Foundation\Application] => app
    [Illuminate\Contracts\Container\Container] => app
    [Illuminate\Contracts\Foundation\Application] => app
    [Psr\Container\ContainerInterface] => app
    [Illuminate\Auth\AuthManager] => auth
    [Illuminate\Contracts\Auth\Factory] => auth
    ...
]
*/

singleton Kernel 和异常处理

原始代码

step 01:singleton

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

step 02:bind

// 抽象类绑定到实体类
$this->bind($abstract, $concrete, true);

step 03:bind code

// 如果没有给定实体类型, 我们简单设置实体类型为虚拟类型, 在那之后
// 在此之后,将注册为共享的具体类型,而不需要在两个参数中强制声明它们的类
$this->dropStaleInstances($abstract);
if (is_null($concrete)) {
    $concrete = $abstract;
}
// 如果工厂不是闭包,这意味着它只是一个类名,它被绑定到这个容器中
// 我们把抽象类型包装在它自己的闭包中,以便在扩展时给我们更多的便利。
if (! $concrete instanceof Closure) {
    $concrete = $this->getClosure($abstract, $concrete);
}
$this->bindings[$abstract] = compact('concrete', 'shared');
// 如果这个类型已经存在, 我们触发重新绑定
if ($this->resolved($abstract)) {
    $this->rebound($abstract);
}