Learning materials:
laravel underlying core code analysis core concept
Laravel (5.5.33) Loading process---instance method
Service container and service provider
Service Container ServiceContainner
ServiceContainner registers the capabilities provided by ServiceProvider into the service container through dependency injection.
Laravel finds the corresponding service directly through the instantiated object of the container, and then you can directly use the capabilities it provides.
ServiceContainner is an instantiated object of a class. All available services are loaded when it is started, and its methods are parsed and called when it is used.
ServiceProvider
Service providers capable of providing services
//Laravel 的服务提供者 config/app.php
'providers' => [
/*
* Laravel Framework Service Providers...
*/
//框架自带 Service Provider
/*
* Package Service Providers...
*/
//需要引入的 Service Provider
]
Laravel source code analysis
Service container $app
/bootstrap/app.php
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
The $app service container is an instantiated object of the Application class.
src/Illuminate/Foundation/Application.php
public function __construct($basePath = null)
{
if ($basePath) {
$this->setBasePath($basePath);//设置基础路径
}
$this->registerBaseBindings();//注册基础绑定
$this->registerBaseServiceProviders();//注册基础服务提供者
$this->registerCoreContainerAliases();//注册核心服务容器别名
}
Register basic binding
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 function
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 function
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;
}
The register function in EventServiceProvider
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 functions
vendor/laravel/framework/src/Illuminate/Container/Container.php
singleton function
public function singleton($abstract, $concrete = null)
{
$this->bind($abstract, $concrete, true);
}
bind function
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 function
/**
* $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);
};
}
Summarize
The process of generating a service container:
1. Register to the instances array through the instance and register methods
2. Bind to the bindings array through the singleton and bind methods
Basic flow of app.php
Instantiate the app (
new Illuminate\Foundation\Application()
)
1.1 Run the constructor__construct()
1.1.1 设置基础路径 $this->setBasePath($basePath); 1.1.2 创建并绑定基础服务容器(app,Container) $this->registerBaseBindings(); 1.1.3 注册基础服务提供者 $this->registerBaseServiceProviders(); 1.1.3 注册基础服务别名 $this->registerCoreContainerAliases();
Map the parameters under the App\Http\Kernel::class class to the lluminate\Contracts\Http\Kernel::class class
$app->singleton( Illuminate\Contracts\Http\Kernel::class, App\Http\Kernel::class );
Map the parameters under App\Console\Kernel::class to Illuminate\Contracts\Console\Kernel::class
$app->singleton( Illuminate\Contracts\Console\Kernel::class, App\Console\Kernel::class );
Map the parameters under App\Exceptions\Handler::class to Illuminate\Contracts\Debug\ExceptionHandler::class
$app->singleton( Illuminate\Contracts\Debug\ExceptionHandler::class, App\Exceptions\Handler::class );
5. Return to app resource
return $app;
Create ServiceProvider
How to call bind
第一种
$abstract 'events' //别名
$concrete 匿名函数(功能是创建实例化对象) //比较自由,可以自由给属性赋值
第二种
$abstract 'Illuminate\Foundation\Mix'
$concrete 'Illuminate\Foundation\Mix' => 匿名函数
第三种
$abstract 'Illuminate\Contracts\Http\Kernel::class'
$concrete 'App\Http\Kernel::class' => 匿名函数 //只能实现构造函数中声明的属性和依赖
Result: bind to the $this->bindings array, and execute the constructor
Custom ServiceProvider
Service container class (declare dependencies)
/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()';
}
}
Create ServiceProvider
/Providers/FamilyServiceProvider.php
/**
* 将可以提供服务的对象绑定到bindings中
*/
public function register(){
$this->app->bind('Family','App\Service\Family\FamilyService');
}
Configure alias
/config/app.php
'providers' => [
App\Providers\FamilyServiceProvider::class,
]
transfer
//通过别名调用服务
app('Family')->testPerson();//app()调用make()方法创建实例
//通过服务名调用服务
app('App\Service\Family\FamilyService')->testPerson();
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。