最近闲下来看了下YII2的源代码,并结合网上的资料对容器的概念有了新的理解。所谓容器就是承载东西的一个空间。那么在PHP主流框架中的容器就是装载类的一个储存空间。当然,并不仅仅只是装载而已,它还帮助我们实例化我们需要的对象。但是,PHP框架中的容器并不只是简单的装载和生成对象的功能,它还帮助我们自动解决了依赖的问题。我们都知道,实例化一个对象的时候,会调用构造方法,不管是隐式的默认构造方法还是显式的自定义的构造方法。那么如果在构造方法的参数列表中,包含有类这样的形参,那么容器会自动帮我们把形参转换成对象。并让构造方法顺利执行,完成实例化对象。容器的这两种行为就产生了一下的两个概念:
DI(Dependency Injection):依赖注入。对象实例化,调用带有参数列表的构造函数,没有这些参数,对象无法实例化,这些参数即为依赖。把参数进行处理并通过反射方法实例化对象,这个过程就是注入。
ICO(Inversion of Control):控制反转。对象的创建一般都是通过"new"关键字进行实例化,现在通过容器自动把我们实例化对象。类实例化的控制权发生了转移,即控制反转。
通过对容器的理解和YII源码的参考,为了加深理解,自己也动手写了一段模拟代码:
/** ** 容器 **/ class Container{ /** ** 注册映射 **/ private $binds = []; /** ** 缓存类反射对象 **/ private $reflections = []; /** ** 类依赖缓存 **/ private $dependents = []; /** ** 注册类声明 ** @param string $class 类名 ** @param string|array|Closure $declaration 类声明定义 ** @param array $params 参数数组 **/ public function bind($class,$declaration){ $this->binds[$class] = $declaration; //获取类构造函数的参数列表,即实例化对象的依赖关系 $this->setDependents($class); } /** ** 获取类的实例化对象 **/ public function get($class,$params=null){ /** ** 确保已注册了类声明信息 **/ if(isset($this->binds[$class])){ /** ** 解决依赖,用于把构造函数里面的依赖对象进行实例化 **/ $this->resolveDependents($class); /** ** DI(依赖注入):把准备好的构造函数的参数列表数组通过反射的方法注入到类的构造函数中,进行对象实例化 IOC(控制反转): 通过容器来实例化对象,并返回 **/ $reflectionClassObj = $this->reflections[$class]; $obj = $reflectionClassObj->newInstanceArgs($this->dependents[$class]); //返回对象 return $obj; }else{ /** ** Code:当未注册到容器,则直接实例化对象 **/ throw new \Exception("Not find " . $class . " from container"); exit(1); } } /** ** 设置类的依赖,并保存ReflectionClass对象 **/ public function setDependents($class){ if(!isset($this->dependents[$class])){ $reflectionClassObj = new ReflectionClass($class); /** ** 缓存类的ReflectionClass对象 **/ $this->reflections[$class] = $reflectionClassObj; /** ** 通过反射获取类的构造函数参数信息列表,简称为依赖,并缓存依赖信息。 **/ $constructor = $reflectionClassObj->getConstructor(); if(!is_null($constructor)){ $params = $constructor->getParameters(); $this->dependents[$class] = $params; }else{ $this->dependents[$class] = []; } } } /** ** 解析依赖 **/ public function resolveDependents($class){ if(isset($this->dependents[$class])){ $dependents = $this->dependents[$class]; foreach($dependents as $k=>$v){ //如果不为NULL,则表示这个参数是一个类,接口,则进行实例化 if($v->getClass() != null){ $this->dependents[$class][$k] = $this->get($v->getName()); } } } } } /** ** Database操作类 **/ class Db{ public function find(){ echo "~~~~~~Search~~~~~~"; } } /** ** 用户操作Model **/ class User{ private $db; public function __construct(Db $db){ $this->db = $db; } public function findAll(){ $this->db->find(); } } //注册到容器 $container = new Container(); $container->bind(‘db‘,‘Db‘); $container->bind("user","User"); $user = $container->get("user"); //获取User对象,容器自动解决依赖并创建对象 $user->findAll(); //echo "~~~~~~Search~~~~~~",也表示实例化的时候,也注入了Db对象
时间: 2024-10-24 04:37:20