前言通过实现laravel框架的功能,可以深入了解laravel框架的先进思想。什么是服务容器服务容器是用来管理类依赖和运行依赖注入的工具。在Laravel框架中,服务容器用于实现控制反转和依赖注入。什么是控制反转(IoC)和依赖注入(DI)控制反转(IoC)是转移创建对象的控制权。以前创建对象的主动权和时机都是自己掌握的,现在这个权力交给了第三方,也就是Laravel中的容器。依赖注入(DependencyInjection,DI)是帮助容器在运行过程中动态提供资源给对象提供依赖。概念简单又不易理解,例如://我们建立一个人类类和一个狗类classPeople{public$dog=null;公共函数__construct(){$this->dog=newDog();}publicfunctionputDog(){return$this->dog->dogCall();}}classDog{publicfunctiondogCall(){return'Wow,woof';,于是他让狗咬人$people=newPeople();$people->putDog();在这个操作中,people类需要依赖Dog类来执行putDog()方法。人们使用构造函数来添加这个Dog依赖项。如果你使用控制反转依赖注入,它看起来像这个类People{public$dog=null;公共函数__construct(Dog$Dog){$this->dog=$dog;}publicfunctionputDog(){return$this->dog->dogCall();}}People类通过构造参数声明自己需要的依赖类,由容器自动注入。这样就实现了程序的有效解耦,好处就不说了。Laravel容器依赖注入的实现原理需要知道的知识点:闭包(匿名函数):匿名函数(Anonymousfunctions),也称为闭包函数(closures),允许临时创建一个没有指定名称的函数反射:PHP5以上版本拥有完整的反射API,增加了对类、接口、函数、方法和扩展进行逆向工程的能力。此外,反射API提供了在函数、类和方法中提取文档注释的方法。了解了闭包和反射的基本用法后,我们再看看Laravel中容器是如何实现的。下面的代码是我对laravel框架容器的一些代码进行的简化。核心版本:lassContainer{/***容器绑定,用于安装提供的实例或提供实例的回调函数*@vararray*/public$building=[];/***注册到容器的绑定*/publicfunctionbind($abstract,$concrete=null,$shared=false){if(is_null($concrete)){$concrete=$abstract;}if(!$concreteinstanceOfClosure){$concrete=$this->getClosure($abstract,$concrete);$this->building[$abstract]=compact("concrete","shared");}//注册一个共享绑定单例publicfunctionsingleton($abstract,$concrete,$shared=true){$this->bind($abstract,$concrete,$shared);}/***生成实例的默认回调闭包**@param$abstract*@param$concrete*@returnClosure*/publicfunctiongetClosure($abstract,$concrete){returnfunction($c)use($abstract,$混凝土){$方法=($a抽象==$具体)?“构建”:“制作”;返回$c->$method($concrete);};}/***构建实例*/publicfunctionmake($abstract){$concrete=$this->getConcrete($abstract);如果($this->isBuildable($concrete,$abstract)){$object=$this->build($concrete);}else{$object=$this->make($concrete);}返回$对象;}/***获取绑定的回调函数*/publicfunctiongetConcrete($abstract){if(!isset($this->building[$abstract])){return$abstract;}返回$this->building[$abstract]['concrete'];}/***判断是否可以创建服务实体*/publicfunctionisBuildable($concrete,$abstract){return$concrete===$abstract||$具体闭包实例;}/***根据实??例具体名称实例具体对象*/publicfunctionbuild($concrete){if($concreteinstanceofClosure){return$con克里特岛($这个);}//创建反射对象$reflector=newReflectionClass($concrete);if(!$reflector->isInstantiable()){//抛出异常thrownew\Exception('无法实例化');}$constructor=$reflector->getConstructor();if(is_null($constructor)){返回新的$concrete;}$dependencies=$constructor->getParameters();$instance=$this->getDependencies($dependencies);返回$reflector->newInstanceArgs($instance);}//通过反射解决参数依赖publicfunctiongetDependencies(array$dependencies){$results=[];foreach($dependencies作为$dependency){$results[]=is_null($dependency->getClass())?$this->resolvedNonClass($dependency):$this->resolvedClass($dependency);}返回$结果;}//解决没有类型提示的依赖publicfunctionresolvedNonClass(ReflectionParameter$parameter){if($parameter->isDefaultValueAvailable()){返回$parameter->getDefaultValue();}抛出新的\Exception('Error');}//通过容器解决依赖publicfunctionresolvedClass(ReflectionParameter$parameter){return$this->make($parameter->getClass()->name);}}容器的工作流程按照上面遛狗的例子://实例化容器类$app=newContainer();//填充容器Dog$app->bind('Dog','App\Dog');//填充People$app->bind('People','App\People');//通过容器实现依赖注入,完成类Instantiate;$people=$app->make('People');//调用方法echo$people->putDog();在上面的例子中,我们首先实例化容器类,然后使用bind()方法绑定接口并生成对应实例的闭包函数,然后使用make()函数生成实例对象。在make()中,将调用isBuildable($concrete,$abstract)以确定是否可以创建给定的服务实体($concrete参数)。可以Create会调用build($concrete)函数,build($concrete)函数会判断传入的参数是闭包还是具体类名,如果是闭包就直接运行,如果是具体类name,会通过反射获取到类的构造函数完成实例化所需的Dependencies。重点理解反射在下面函数中的用法,应该对build($concrete)getDependencies(array$dependencies)resolvedNonClass(ReflectionParameter$parameter)resolvedClass(ReflectionParameter$parameter)理解得很好最后,IoC有点难理解,可能文章中的描述让你感觉不清楚。在PHP中可以使用debug观察文章中代码的运行情况。了解了容器的具体实现原理后,再看Laravel中的相关实现,你会觉得豁然开朗。
