源码阅读 Application : make

1
2
3
4
5
6
7
8
// 1) Alias 解析
$abstract = $this->getAlias($abstract);
// 2) 如果是延迟加载且尚未实例化
if (isset($this->deferredServices[$abstract]) && ! isset($this->instances[$abstract])) {
$this->loadDeferredProvider($abstract);
}
// 3) parent::make
return parent::make($abstract, $parameters);

1) Alias 解析

getAlias

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// aliases sample
/* $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
...
]
*/
// 如果未设置
// 返回 Illuminate\Foundation\Application
if (! isset($this->aliases[$abstract])) {
return $abstract;
}
if ($this->aliases[$abstract] === $abstract) {
throw new LogicException("[{$abstract}] is aliased to itself.");
}
return $this->getAlias($this->aliases[$abstract]);

2) 延迟加载 Provider (loadDeferredProvider())

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// aliases sample
/* $this->deferredServices = [
[Illuminate\Bus\Dispatcher] => Illuminate\Bus\BusServiceProvider
[Illuminate\Contracts\Bus\Dispatcher] => Illuminate\Bus\BusServiceProvider
[Illuminate\Contracts\Bus\QueueingDispatcher] => Illuminate\Bus\BusServiceProvider
[cache] => Illuminate\Cache\CacheServiceProvider
[cache.store] => Illuminate\Cache\CacheServiceProvider
[memcached.connector] => Illuminate\Cache\CacheServiceProvider
...
]
*/
if (! isset($this->deferredServices[$service])) {
return;
}
$provider = $this->deferredServices[$service];
// 如果 service provider 尚未加载, 我们可以加载这个服务, 然后从这个列表中移除
if (! isset($this->loadedProviders[$provider])) {
// 1) 注册延迟加载的服务提供者
$this->registerDeferredProvider($provider, $service);
}

2-1) 注册延迟加载的服务提供者

1
2
3
4
5
6
7
8
9
10
// 已经注册, 我们会把这个东西从列表中移除
if ($service) {
unset($this->deferredServices[$service]);
}
$this->register($instance = new $provider($this));
if (! $this->booted) {
$this->booting(function () use ($instance) {
$this->bootProvider($instance);
});
}

3) parent::make 来创建应用

来源创建值

1
$abstract   = Illuminate\Contracts\Http\Kernel::class

函数解析

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
// 获取关联
$abstract = $this->getAlias($abstract);
$needsContextualBuild = ! empty($parameters) || ! is_null(
$this->getContextualConcrete($abstract)
);
// 如果是单例, 我们只需要返回唯一的实例, 不需要重新创建. 保证开发者使用同一个实例
if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
return $this->instances[$abstract];
}
$this->with[] = $parameters;
// 获取实例类型
$concrete = $this->getConcrete($abstract);
// 根据绑定来注册实例, 这个根据内部来加载到所有依赖
if ($this->isBuildable($concrete, $abstract)) {
// 1) build
$object = $this->build($concrete);
} else {
// 不可创建则视为存在, 则返回
$object = $this->make($concrete);
}
// 如果我们定义了扩展器, 我们必须应用这些修饰扩展
foreach ($this->getExtenders($abstract) as $extender) {
$object = $extender($object, $this);
}
// 如果注册为 singleton 模式 , 我们直接返回
if ($this->isShared($abstract) && ! $needsContextualBuild) {
$this->instances[$abstract] = $object;
}
// 触发回调
$this->fireResolvingCallbacks($abstract, $object);
// 在返回前, 需要标注标识, 并且移除 with 参数.
$this->resolved[$abstract] = true;
array_pop($this->with);
return $object;

3-1) 使用 build 来创建对象

Illuminate/Container/Container::build(Illuminate\Contracts\Http\Kernel::class)

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
// 如果实例类型是 闭包函数, 我们执行并且返回这些对象
// 这里的 app 应该是对应的 Application,
if ($concrete instanceof Closure) {
return $concrete($this, $this->getLastParameterOverride());
}
// 初始化映射类
$reflector = new ReflectionClass($concrete);
// 如果不能实例化, 尽早脱离出来, 不要再执行
if (! $reflector->isInstantiable()) {
return $this->notInstantiable($concrete);
}
$this->buildStack[] = $concrete;
// 通过映射类获取构造器
$constructor = $reflector->getConstructor();
// 如果没有构造器, 我们按照类的处理方式来返回一个新建的对象
if (is_null($constructor)) {
array_pop($this->buildStack);
return new $concrete;
}
// 获取参数
$dependencies = $constructor->getParameters();
// 一旦我们获取所有的构造器参数, 我们能创建每一个依赖示例, 并且传入.
$instances = $this->resolveDependencies(
$dependencies
);
array_pop($this->buildStack);
// 根据给定的参数创建新实例(这就是传说中的自动注入(-WAIT-)?)
return $reflector->newInstanceArgs($instances);

原文地址 : 源码阅读 Application : make
本站是作者语雀文档的镜像站, 如对文章有任何疑问请移步语雀进行 提问

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

初始化 Application

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

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

Illuminate/Foundation/Application::__construct()

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

1) 注册基本绑定

1
2
3
4
5
6
# 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)为例子来阅读源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 移除抽象关联
$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) 注册事件处理

1
2
3
4
5
6
// 注册事件处理器
$this->register(new EventServiceProvider($this));
// 注册日志服务
$this->register(new LogServiceProvider($this));
// 注册路由服务
$this->register(new RoutingServiceProvider($this));

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

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
/* 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

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

2-3) LogServiceProvider

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

2-4) RoutingServiceProvider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 注册路由
$this->registerRouter();
// url 生成
$this->registerUrlGenerator();
// 定向器
$this->registerRedirector();
// psr 请求
$this->registerPsrRequest();
// psr 响应
$this->registerPsrResponse();
// 响应工厂
$this->registerResponseFactory();
// 控制器触发器
$this->registerControllerDispatcher();

3) 注册 Alias

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$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 项目

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
$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 结果

1
2
3
4
5
6
7
8
9
10
/* $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

1
2
3
4
$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);

step 02:bind

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

step 03:bind code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 如果没有给定实体类型, 我们简单设置实体类型为虚拟类型, 在那之后
// 在此之后,将注册为共享的具体类型,而不需要在两个参数中强制声明它们的类
$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);
}

原文地址 : 源码阅读 - 初始 : (2) 初始化 App
本站是作者语雀文档的镜像站, 如对文章有任何疑问请移步语雀进行 提问