学习资料:
laravel底层核心代码分析核心概念
Laravel (5.5.33) 加载过程---instance方法
服务容器和服务提供者
服务容器 ServiceContainner
ServiceContainner通过依赖注入将ServiceProvider提供的能力注册进服务容器内部。
Laravel直接通过容器的实例化对象,找到对应的服务,就可以直接使用其提供的能力了。
ServiceContainner就是一个类的实例化对象,启动时加载所有可用服务,用的时候再解析调用其中的方法。
服务提供者 ServiceProvider
有能力提供服务的服务提供者
//Laravel 的服务提供者 config/app.php
'providers' => [
/*
* Laravel Framework Service Providers...
*/
//框架自带 Service Provider
/*
* Package Service Providers...
*/
//需要引入的 Service Provider
]
Laravel源码解析
服务容器 $app
/bootstrap/app.php
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
$app服务容器,就是Application类的实例化对象。
src/Illuminate/Foundation/Application.php
public function __construct($basePath = null)
{
if ($basePath) {
$this->setBasePath($basePath);//设置基础路径
}
$this->registerBaseBindings();//注册基础绑定
$this->registerBaseServiceProviders();//注册基础服务提供者
$this->registerCoreContainerAliases();//注册核心服务容器别名
}
注册基础绑定
src/Illuminate/Foundation/Application.php
protected function registerBaseBindings()
{
static::setInstance($this);//实例化自己
$this->instance('app', $this);//将app注册到instances数组中
$this->instance(Container::class, $this);//将Container注册到instances数组中
$this->singleton(Mix::class);
$this->singleton(PackageManifest::class, function () {
return new PackageManifest(
new Filesystem, $this->basePath(), $this->getCachedPackagesPath()
);
});
}
instance函数
vendor/laravel/framework/src/Illuminate/Container/Container.php
/**
* $abstract 'app' $instance Application
* $abstract Container::class $instance Application
*/
public function instance($abstract, $instance)
{
$this->removeAbstractAlias($abstract); //删除抽象别名
$isBound = $this->bound($abstract);//判断是否实例化
unset($this->aliases[$abstract]); //删除别名
//将实例加入instances数组
$this->instances[$abstract] = $instance;
//如果之前存在实例化 则运行
if ($isBound) {
$this->rebound($abstract);
}
return $instance;
}
register函数
src/Illuminate/Foundation/Application.php
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);
}
if (method_exists($provider, 'register')) {
$provider->register();//调用ServiceProvider实例的register方法
}
//标记为已注册
$this->markAsRegistered($provider);
//判断App是否已启动,已创建则调用$provider的启动(boot)方法
if ($this->booted) {
$this->bootProvider($provider);
}
return $provider;
}
EventServiceProvider中的register函数
public function register()
{
$this->app->singleton('events', function ($app) {
return (new Dispatcher($app))->setQueueResolver(function () use ($app) {
return $app->make(QueueFactoryContract::class);
});
});
}
singleton,bind,getClosure函数
vendor/laravel/framework/src/Illuminate/Container/Container.php
singleton函数
public function singleton($abstract, $concrete = null)
{
$this->bind($abstract, $concrete, true);
}
bind函数
public function bind($abstract, $concrete = null, $shared = false)
{
//从instances和aliases数组中移除$abstract
$this->dropStaleInstances($abstract);
if (is_null($concrete)) {
$concrete = $abstract;
}
//如果$concrete不是匿名函数,则将$concrete转化为匿名函数
if (! $concrete instanceof Closure) {
$concrete = $this->getClosure($abstract, $concrete);
}
//$abstract加入bindings数组
$this->bindings[$abstract] = compact('concrete', 'shared');
//如果抽象类型已在此容器中解析,我们将触发恢复侦听器,以便已解析的任何对象可以通过侦听器回调更新对象的副本。
if ($this->resolved($abstract)) {
$this->rebound($abstract);
}
}
getClosure函数
/**
* $abstract Mix $concrete Mix => Closure
*/
protected function getClosure($abstract, $concrete)
{
return function ($container, $parameters = []) use ($abstract, $concrete) {
if ($abstract == $concrete) {
return $container->build($concrete);
}
return $container->make($concrete, $parameters);
};
}
总结
生成服务容器的过程:
1.通过instance和register方法注册到instances数组
2.通过singleton和bind方法绑定到bindings数组
app.php基本流程
实例化app (
new Illuminate\Foundation\Application()
)
1.1 运行构造函数__construct()
1.1.1 设置基础路径 $this->setBasePath($basePath); 1.1.2 创建并绑定基础服务容器(app,Container) $this->registerBaseBindings(); 1.1.3 注册基础服务提供者 $this->registerBaseServiceProviders(); 1.1.3 注册基础服务别名 $this->registerCoreContainerAliases();
把App\Http\Kernel::class类下的参数映射到lluminate\Contracts\Http\Kernel::class类中
$app->singleton( Illuminate\Contracts\Http\Kernel::class, App\Http\Kernel::class );
把App\Console\Kernel::class类下的参数映射到Illuminate\Contracts\Console\Kernel::class类中
$app->singleton( Illuminate\Contracts\Console\Kernel::class, App\Console\Kernel::class );
把App\Exceptions\Handler::class类下的参数映射到Illuminate\Contracts\Debug\ExceptionHandler::class类中
$app->singleton( Illuminate\Contracts\Debug\ExceptionHandler::class, App\Exceptions\Handler::class );
5.返回app资源
return $app;
创建ServiceProvider
bind的调用方式
第一种
$abstract 'events' //别名
$concrete 匿名函数(功能是创建实例化对象) //比较自由,可以自由给属性赋值
第二种
$abstract 'Illuminate\Foundation\Mix'
$concrete 'Illuminate\Foundation\Mix' => 匿名函数
第三种
$abstract 'Illuminate\Contracts\Http\Kernel::class'
$concrete 'App\Http\Kernel::class' => 匿名函数 //只能实现构造函数中声明的属性和依赖
结果:绑定到$this->bindings数组,并执行构造函数
自定义ServiceProvider
服务容器类(声明依赖关系)
/Service/Family/FamilyService.php
<?php
namespace App\Service\Family;
class FamilyService{
public function __construct(PersonService $person,TvService $tv){
$this->person = $person;
$this->tv = $tv;
echo 'Instance FamilyService';
}
public function testPerson(){
$this->persion->test();
}
}
/Service/Family/PersonService.php
<?php
namespace App\Service\Family;
class PersonService{
public function __construct(){
echo 'Instance PersonService';
}
public function test(){
echo 'PersonService test()';
}
}
/Service/Family/TvService.php
<?php
namespace App\Service\Family;
class TService{
public function __construct(){
echo 'Instance TvService';
}
public function test(){
echo 'TvService test()';
}
}
创建ServiceProvider
/Providers/FamilyServiceProvider.php
/**
* 将可以提供服务的对象绑定到bindings中
*/
public function register(){
$this->app->bind('Family','App\Service\Family\FamilyService');
}
配置别名
/config/app.php
'providers' => [
App\Providers\FamilyServiceProvider::class,
]
调用
//通过别名调用服务
app('Family')->testPerson();//app()调用make()方法创建实例
//通过服务名调用服务
app('App\Service\Family\FamilyService')->testPerson();
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。