云智慧(北京)科技有限公司
一、IoC的概念介绍
控制反转(IOC)模式(又称DI:DependencyInjection)就是Inversion ofControl,控制反转。在Java开发中,IoC意 味着将你设计好的类交给系统去控制,而不是在你的类内部控制。这称为控制反转。
IoC(Inversion of Control)是近年来兴起的一种思想,不仅仅是编程思想。主要是协调各组件间相互的依赖关系,同时大大提高了组件的可移植性,组件的重用机会也变得更多。在传统的实现中,由程序内部代码来控制程序之间的关系。我们经常使用new关键字来实现两组键间关系的组合,这种实现的方式会造成组件之间耦合(一个好的设计,不但要实现代码重用,还要将组件间关系解耦)。IoC很好的解决了该问题,它将实现组件间关系从程序内部提到外部容器来管理。也就是说由容器在运行期将组件间的某种依赖关系动态的注入组件中。控制程序间关系的实现交给了外部的容器来完成。即常说的好莱坞原则“Don't call us, we'll call you”。
那么,在Laravel框架中Ioc模式是如何实现的呢?
二、Laravel框架中Ioc模式的实现方式
1.请求实现的流程图
在请求流程图中可以看到有两个比较重要的文件start.php和Application.php,其中,start.php文件中引入了全局变量$app = new IlluminateFoundationApplication;注意该全局变量$app就是为我们解决所有注入依赖关系的“管家婆”,它会把应用中所用到的工具类提前存储起来,当用到的时候可以随时的提取。
2.采用数组的方式管理对象
lluminateFoundationApplication类继承了laravel的容器Container和php的标准接口ArrayAccess,从而实现了数组方式管理对象。
php的标准接口ArrayAccess中包含了四个属性:
下面是ArrayAccess 的定义:
interface ArrayAccess
boolean offsetExists($index)
mixed offsetGet($index)
void offsetSet($index, $newvalue)
void offsetUnset($index)
Application类中继承的container类对这四个抽象方法进行了重写,实现了应用中所用到的功能。Container类中的两个属性$bindings和$instances是用来存放实际应用中所用到的工具类实例。这样我们就可以通过$app[‘工具类的别名’]或者通过“工具类的别名::方法名”的方式来调用真正的工具类实例中的方法。
列如,路由中常用的方式: Route::post(‘url’,’controller@method’);
将服务注册到$app全局变量中,laravel的实现方式是读取app/config/app.php配置,并将
'providers' => array(
'IlluminateFoundationProvidersArtisanServiceProvider',
'IlluminateAuthAuthServiceProvider',
'IlluminateCacheCacheServiceProvider',
'IlluminateSessionCommandsServiceProvider',
'IlluminateFoundationProvidersConsoleSupportServiceProvider',
'IlluminateRoutingControllerServiceProvider',
'IlluminateCookieCookieServiceProvider',
'IlluminateDatabaseDatabaseServiceProvider',
'IlluminateEncryptionEncryptionServiceProvider',
'IlluminateFilesystemFilesystemServiceProvider',
'IlluminateHashingHashServiceProvider',
'IlluminateHtmlHtmlServiceProvider',
'IlluminateLogLogServiceProvider',
'IlluminateMailMailServiceProvider',
'IlluminateDatabaseMigrationServiceProvider',
'IlluminatePaginationPaginationServiceProvider',
'IlluminateQueueQueueServiceProvider',
'IlluminateRedisRedisServiceProvider',
'IlluminateRemoteRemoteServiceProvider',
'IlluminateAuthRemindersReminderServiceProvider',
'IlluminateDatabaseSeedServiceProvider',
'IlluminateSessionSessionServiceProvider',
'IlluminateTranslationTranslationServiceProvider',
'IlluminateValidationValidationServiceProvider',
'IlluminateViewViewServiceProvider',
'IlluminateWorkbenchWorkbenchServiceProvider',
),
通过IlluminateFoundationstart.php文件中的
$providers = $config['providers'];
$app->getProviderRepository()->load($app,$providers);
注入到$app中。同时,在该文件中还会执行
$aliases = $config['aliases'];
AliasLoader::getInstance($aliases)->register();
这样就可以实现使用别名访问想要运行的服务了。
利用控制反转和别名的好处:
Laravel中通过控制反转的方式可以解决相同的调用方式,但可以采取不同的实现方式。这样我们就不用更改业务逻辑中的代码,就能更换不同的解决问题的方式。
例如,Laravel用到的Cache,在业务逻辑代码中只需要使用Cache::set(),就可以设置cache缓存了。但是,具体是用什么方式做的cache我们是不用关心的。因为,$app[‘cache’]中即可以存放redis的实例,也可以存放memcache的实例,这个是可以通过配置文件来确定的。
如果要是用传统的cache方式,将会是Redis::set()或者是Memcache::set()的方式,这样我们在想换不同的cache存储方式的时候就要通过更改业务逻辑代码才能完成。