<输入的最好方式就是输出>,本着学习的态度表达一下自己浅显的理解。IOC(Inversion of Control),即控制反转,是面向对象中的一种设计原则。下面我将简单介绍IOC的作用和实现原理,最后用具体的示例应用来帮助加深理解。
1、IOC的作用
IOC可以作为依赖对象的统一管理者,从而降低代码的耦合性,提升程序的可维护性。
2、实现原理
IOC作为管理依赖的容器,涉及的相关技术是反射和依赖注入。
下面将简单介绍PHP反射和依赖注入。
-
PHP反射
简单概括就是对象的自省能力,对象通过反射获取其类的信息。
示例代码:
$node = new LinkNode();//实例化对象
$nodeClass = new ReflectionClass($node);//通过对象获取其反射类
$properties = $nodeClass->getProperties();//获取类的所有属性
$methods = $nodeClass->getMethods();//获取类的所有方法
-
依赖注入
DI(dependency injection),即依赖注入,它是IOC的实现方式之一。下面将介绍PHP-DI相关原理(参考文档:https://php-di.org/doc/getting-started.html),以下是文档部分内容:
1-php-di
上图代码块介绍了依赖注入的作用,例子中UserManager类需要依赖Mailer类。通过注入的方式可避免手动实例化依赖对象,即调用UserManager时可以不用手动实例化依赖对象。
标红的两块则是IOC容器实现依赖注入的技术,autowiring(自动装载)和PHP's Reflection classes(PHP反射类)。autowiring可以扫描代码找到类的构造函数所需要的参数是什么(本例中是Mailer对象),php-di通过php反射类即可找到Mailer类并实例化对象。php反射类前面已经介绍过了,下面介绍下autowiring的原理。
上图第一个红框表明,容器可以通过自动装载自动创建和注入依赖;第二个红框表示注入的过程等同于先实例化对象,再传递给构造函数的参数。另外文档还指出,构造函数的参数必须要有类型提示才能实现注入。
php-di注入的方式其实不止autowiring这一种,总共有三种:autowiring(自动装载)、annotation(注解)、PHP definitions(PHP定义),感兴趣的小伙伴可以自行查阅文档相关内容。
总结:IOC容器通过依赖注入的方式帮我们管理类的依赖关系,而不需要我们手动去管理依赖(实例化依赖对象)。本文的php依赖注入利用php反射找到依赖信息,autowiring自动加载实现构造参数的注入。
3、示例应用(Laravel)
纸上得来终觉浅,简单介绍完IOC容器的实现原理,现在以laravel为例具体实践应用一下,有助于加深理解。示例主要涉及两个层面,一个将类的依赖关系绑定到容器;另一个是从容器中解析类。
Laravel官方文档
英文版:https://laravel.com/docs/8.x/container#when-to-use-the-container
中文版:https://learnku.com/docs/laravel/8.5/container/10365#120d42
- IOC容器绑定类的依赖关系
在这个例子中,Transistor是要绑定的类,它的依赖类是PodcastParser。如果 PodcastParser类自身也存在依赖,容器会根据它所绑定的依赖关系,递归地 解析相应的依赖。use App\Services\Transistor; use App\Services\PodcastParser; $this->app->bind(Transistor::class, function ($app) { return new Transistor($app->make(PodcastParser::class)); });
需要注意的是,如果PodcastParser没有在容器中绑定过,使用容器解析作为依赖会报错,即不能使用$app->make(PodcastParser::class),而应该使用new PodcastParser()
- IOC容器的使用
IOC容器的使用可以分为两步,依赖注入和make解析获取对象;
1 依赖注入分为构造函数注入和set函数注入。
2 Laravel中解析容器对象,可以使用助手函数从容器中解析获取:app()->make(PodcastParser::class);
【另外,Laravel中的Facade门面类(静态代理类)本质也是通过容器解析对象;指定类要绑定别名至容器,同时对应的静态类要继承Facade类并重写getFacadeAccessor方法指定绑定别名,之后就能使用门面类实例对象了。】
以上只是简单介绍了一下Laravel容器的依赖绑定和使用,方便理解IOC容器的运作过程。
实际上绑定过程还涉及到Laravel的核心<服务提供者>,我们需要在提供者的register注册方法中绑定相关依赖;绑定的类型也有很多种,可分为单例绑定(每次解析都是单例对象),接口绑定(自动解析注入的接口为指定实现类)等等,这边暂时不展开,感兴趣的小伙伴可以自行查阅文档。
网友评论