Laravel学习笔记(29)Laravel的核心概念(服务容器概念,依赖注入,绑定,服务提供者,外观)

  1. 什么是服务器容器
    服务容器就是一个普通的容器,用来装类的实例,然后在需要的时候再取出来。用更专业的术语来说是服务容器实现了控制反转(Inversion of Control,缩写为 IoC),意思是正常情况下类 A 需要一个类 B 的时候,我们需要自己去 new 类 B,意味着我们必须知道类 B 的更多细节,比如构造函数,随着项目的复杂性增大,这种依赖是毁灭性的。控制反转的意思就是,将类 A 主动获取类 B 的过程颠倒过来变成被动,类 A 只需要声明它需要什么,然后由容器提供。

这样做的好处是,类 A 不依赖于类 B 的实现,这样在一定程度上解决了耦合问题。

在 Laravel 的服务容器中,为了实现控制反转,可以有以下两种:

依赖注入(Dependency Injection)。
绑定。

  1. 什么是解耦

简而言之:A类不再直接依赖B类,而是在A类和B类之间生成一个缓冲区,利用这个缓冲区传递数据

  1. 什么是依赖注入

简而言之:A类调用B类的方法的时候,不在A类中实例化一个B类的对象,而是只在函数中引入B类的对象(举例用构造函数),并在A类中保存后调用。而实例化B类的过程,放在了A类外部。

传统方法

clas A {
	public function __construct() {
		$this->obj = new B();
	}
}

$a = new A()

依赖注入方法

clas A {
	public function __construct(B $b) {
		$this->obj = $b;
	}
}

$b = new B();
$a = new A($b);

PS:PHP中为了解决依赖注入的一些问题,引入了接口类的概念(Interface

  1. PHP和Laravel的生命周期
1. 模块初始化(MINIT),即调用 php.ini 中指明的扩展的初始化函数进行初始化工作,如 mysql 扩展。
2. 请求初始化(RINIT),即初始化为执行本次脚本所需要的变量名称和变量值内容的符号表,如 $_SESSION 变量。
3. 执行该 PHP 脚本。(Lravel生命周期开始)
	
	3.1 注册加载 composer 自动生成的 class loader,包括所有你 composer require 的依赖(对应代码 1.
	3.2 生成容器 Container,Application 实例,并向容器注册核心组件。这里牵涉到了容器 Container 和合同 Contracts,以及依赖注入等问题
	3.3 处理请求,生成并发送响应(对应代码 3,毫不夸张的说,你 99% 的代码都运行在这个小小的 handle 方法里面)。(具体代码的实现位置)
	3.4 请求结束,进行回调(对应代码 4,还记得可终止中间件吗?没错,就是在这里回调的)。

4. 请求处理完成 (Request Shutdown),按顺序调用各个模块的 RSHUTDOWN 方法,对每个变量调用 unset 函数,如 unset $_SESSION 变量。
5. 关闭模块 (Module Shutdown)PHP 调用每个扩展的 MSHUTDOWN 方法,这是各个模块最后一次释放内存的机会。这意味着没有下一个请求了。

PS:其他文档

使用  bind()/singleton()  方法把容器与接口具体的实现类进行绑定:
app()->bind(MyInterface::class, MyClass::class);  // 使用一次绑定一次,下一次需要重新绑定
app()->singleton(MyInterface::class, MyClass::class);  // 一个周期只绑定一次,下一次不需要绑定

$instance = app()->make(MyInterface::class);
// 相当于
$instance = app(MyInterface::class);
// 相当于
$instance = new MyClass(new AnotherClass());

绑定服务容器

interface Fruit
{
    public function color();
}

class Apple implements Fruit
{
    public $color;

    public function __construct($color){
        $this->color = $color;
    }

    public function color(){
        return $this->color;
    }
}

app()->bind('Fruit', 'Apple');
// 当类Apple需要$color参数的时候,将red传给他
app()->bind(Fruit::class, Apple::class);
app()->when(Apple::class)->needs('$color')->give('22');
echo app(Fruit::class)->color();
  1. 服务提供者Server Provider

用于绑定类到容器中
相当于将药片(类)放入药箱(容器)的小格子中(服务提供者),每个格子管理一种药片

// 新建一个服务提供者
php artisan make:provider AbcServiceProvider

解析顺序为:

// public/index.php
$app = require_once __DIR__.'/../bootstrap/app.php';// 注册核心服务

$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

// bootstrap/app.php
$app->singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
);
// vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php,执行handle方法中的sendRequestThroughRouter
    public function handle($request) {
    	...
    	$response = $this->sendRequestThroughRouter($request);
    }
	// 在sendRequestThroughRouter方法中再执行bootstrap()
   \Illuminate\Foundation\Bootstrap\RegisterProviders::class,

// 因为执行的是根据config/app.php加载的providers,例如
     /*
      * Application Service Providers...
      */
     App\Providers\AppServiceProvider::class,
     App\Providers\AuthServiceProvider::class,
     // App\Providers\BroadcastServiceProvider::class,
     App\Providers\EventServiceProvider::class,
     App\Providers\RouteServiceProvider::class,

所以要在config/app.php中注册AbcServiceProvider

之后在AbcServiceProvider中绑定类和容器

class AbcServiceProvider extends ServiceProvider implements DeferrableProvider
{
    public function register()
    {
        $this->app->singleton(Connection::class, function ($app) {
            return new Connection(config('riak'));
        });
    }

	// 默认生成的方法是没有这个的
	// 使用延时服务提供者后,只有在真正调用这个服务器提供者的时候,才会进行加载,节约内存
	// 实现方法:implements DeferrableProvider和public function provides()和类名Connection::class
	// 可以参考缓存的服务提供者vendor/laravel/framework/src/Illuminate/Cache/CacheServiceProvider.php
    public function provides()
    {
        return [Connection::class];
    }
}
  1. 深入浅出 Laravel 的 Facade 外观系统

加载外观服务有 AliasLoader 组件完成:

首先,会从配置文件 config/app.php 中读取所有的「外观」服务配置 aliases;

再从清单文件中读取别名服务 $app->make(PackageManifest::class)->aliases();

将两个配置数组合并后注入到 AliasLoader 完成 注册(先在使用「外观」服务时动态引入这个类后再进行注册。)

最后后在客户端中调用外观服务时,会调用实现「外观」的 getFacadeAccessor 方法获取到组件(服务或者说接口)的名称;然后从 Laravel 服务容器中解析出相关服务。

发布了40 篇原创文章 · 获赞 0 · 访问量 761

猜你喜欢

转载自blog.csdn.net/qj4865/article/details/104378314