容器。什么是容器?相信很多人都听说过依赖注入。实现依赖注入的基本条件离不开容器。容器用于管理类依赖和注入,负责服务管理和组件解耦。最简单的理解,我们可以把容器理解为一个专门用来存储对象的超大数组。如图1所示,调用者通过容器的标签获取对象实例。从图中可以看出,实例对象可以通过::class的方法获取,也可以直接通过对象标签获取。什么是IOC?你可能听说过IOC容器,IOC的全称是:(InversionOfControl,控制反转)。让我们了解什么是控制反转。在我们传统的编码中,我们类之间的依赖关系通常是通过编码传递新的对象。使用控制反转,我们可以将控制对象交给容器或者框架来实现。目的是让我们无需硬编码即可创建对象。看图1,我们可以看到容器中存放了很多对象,我们想用的时候可以直接使用。容器中的对象不需要我们在代码中编码和创建。当需要类对象时,会去容器中获取对象,如果对象不存在,会自动创建。这是在代码中省略了创建对象的过程,让容器帮我们实现创建的过程。这称为控制反转。一句话概括IOC:将创建对象的控制权转移到容器实现类的实例化上。例如:不使用IOC,我们想创建一个类computer=$computer;}publicfunctionprogram(){$this->computer->run();}}$sunny=newSunny(newComputer());$sunny->program();这里可以看到Sunny要编程的类依赖于Computer类,如果使用IOC容器实现依赖注入,代码就简单了。computer=$computer;}publicfunctionprogram(){$this->computer->run();}}$sunny=Container::getBean(Sunny::class);$sunny->program();一句话总结:解决创建类实例的问题其中,对其他类的依赖动态地为一个对象提供它需要的其他对象。依赖倒置依赖倒置解决了模块之间重度依赖的松散耦合问题。上层模块不应该依赖底层模块,它们都应该依赖抽象。通常,对依赖倒置的简单理解就是针对接口或抽象进行编程。让我们通过下面的例子来了解一下面向接口的编程。类缓存{publicfunctionset($key,$value){$redis=newCFile();$redis->set($key,$value);}}classCFile{publicfunctionset($key,$value){echo"file:{$key}->{$value}\n";}}$cache=newCache();$cache->set("name","sunny");看上面的代码好像没什么大问题,但是万一哪天文件缓存换成Redis缓存呢?classCache{publicfunctionset($key,$value){$redis=newCRedis();$redis->set($key,$value);}}classCRedis{publicfunctionset($key,$value){echo"redis:{$key}->{$value}\n";}}$cache=newCache();$cache->set("name","sunny");通过这段代码可以看出,原来当一个cache使用的driver发生变化时,Cache的代码也必须随之变化,因为代码是硬编码在调用者身上的,耦合度变高了。就像修改代码一样,让程序员针对接口进行编程,让代码变得更加通用和规范。interfaceICache{publicfunctionset($key,$value);}classCRedisimplementsICache{publicfunctionset($key,$value){echo"redis:{$key}->{$value}\n";}}类CFile实现ICache{publicfunctionset($key,$value){echo"file:{$key}->{$value}\n";}}classCache{private$drive;公共函数__construct(ICache$drive){$this->drive=$drive;}publicfunctionset($key,$value){$this->drive->set($key,$value);}}$cache=newCache(newCFile());$cache->set("name","sunny");很多人看到这段代码就想,那我在构造方法中直接传入想要的对象就可以了吗?为什么要定义接口?其实定义接口就是为了规范代码。不管你用哪个驱动,只要实现了我的接口就可以用。没有接口的开发者在开发驱动时,将不知道驱动中应该有哪些方法。我们使用接口后,大家只需要为接口编程即可,Cache并不关心类是如何实现的。Cache只是按照接口的方法进行操作。一句话总结:依赖倒置实现松耦合实战:按照容器原理实现容器[];privatefunction__construct(){}publicstaticfunctiongetInstance(){if(!self::$instance){self::$instance=newstatic();}返回自我::$实例;}/***获取对象实例*@param$key*@returnmixed*/publicfunctionget($key){if(isset($this->instances[$key])){return$this->实例[$键];}}/***将对象、闭包、类绑定到容器*@param$key*@paramnull$concrete*@returnContainer*/publicfunctionbind($key,$concrete=null){if($concreteinstanceofClosure){$this->instances[$key]=$concrete;}elseif(is_object($concrete)){$this->instances[$key]=$concrete;}返回$this;}}classSunny{公共函数getName(){回声时间()."\n";}}$app=Container::getInstance();$sunny=$app->bind(Sunny::class,newSunny());$sunny=$app->get(Sunny::class);$sunny->获取名称();实战:实现依赖注入Container.phpinstances[$key])){return$这个->实例[$键];}返回$this->make($key);}/***将对象、闭包、类绑定到容器*@param$key*@paramnull$concrete*@returnContainer*@throwsReflectionException*/publicfunctionbind($key,$concrete=null){if($concreteinstanceofClosure){$this->instances[$key]=$concrete;}elseif(is_object($concrete)){$this->instances[$key]=$concrete;}else{$this->make($key,$concrete);}返回$this;}/***创建类绑定到类实例*@param$abstract*@paramnull$atgs*@returnmixed*@throwsReflectionException*/publicfunctionmake($abstract,$atgs=null){if(isset($this->instances[$abstract])){return$this->instances[$abstract];}$object=$this->invokeClass($abstract);$this->instances[$abstract]=$object;返回$对象;}/***反射解析类*@param$abstract*@returnobject*@throwsReflectionException*/publicfunctioninvokeClass($abstract){$reflectionClass=new\ReflectionClass($abstract);//获取构造方法$构造=$reflectionClass->getConstructor();//获取参数获取实例$params=$construct?$this->parserParams($construct):[];$object=$reflectionClass->newInstanceArgs($params);返回$对象;}/***解析构造函数参数*@param$reflect*@returnarray*@throwsReflectionException*/publicfunctionparserParams(ReflectionMethod$reflect){$args=[];$params=$reflect->getParameters();如果(!$params){返回$args;}if(count($params)>0){foreach($paramsas$param){$class=$param->getClass();如果($class){$args[]=$this->make($class->getName());继续;}//获取变量名$name=$param->getName();//默认值$def=null;//如果有默认值,则从默认值中获取类型if($param->isOptional()){$def=$param->getDefaultValue();}$args[]=$_REQUEST[$name]??$定义;}}返回$args;}}Test.phptest1=$test1;$this->name=$this->test1->getName();}}测试1。phptest=$test;}publicfunctiongetName(){echo"获取测试中的名称:{$this->test->name}\n";}}$app=Container::getInstance();$sunny=$app->get(Sunny::class);$sunny->getName();如果喜欢我们请关注+转发文章让更多人看到,我们会持续提供更多原创好文章
