php依赖注入与容器,Container,控制反转

依赖注入与Ioc容器

概念:

  1. 容器:可以理解为用来存放某个东西的物品(篮子?),存放的东西取决于你想往里面放点什么。在这里,我们是存放某个类,类的描述或者一个返回类实例的闭包函数。
  2. Ioc(Inversion of Control) 控制反转:可以理解为,你(用户),小红(容器)。你现在需要一把锤子,但你不想自己去造一个锤子去。你可以交给小红去处理。比如对小红说我想要一把锤子。小红会通过你给的工具名(锤子),通过自己的方法。去得到锤子的原材料(类的构造),接着在小红这里,直接造出来了一把锤子,不需要你来动手。你不需要知道这个锤子(类)所需的原材料(这里是指类的构造参数)。你通过小红(容器)而获取到了这个工具(类的实例).
  3. DI(Dependency Injection) 依赖注入:这和Ioc是同一种东西,但不同的是角度。例如:工具(锤子)依赖于小红(容器)去获取工具的原材料,并创建出工具(锤子).

特性:

  1. 减少系统之间的耦合性
  2. 增加代码稳定和健壮性
  3. 也可以理解为工厂模式的一种升级

php大神聚集地:294088839

Demo:

Class Demo1
{
    public $name;
    public function __construct(Demo2 $demo)
    {
        $this->demo = $demo;
    }
    public function Name()
   {
   $this->name = $this->demo->getName();
   return $this->name;
   }
}
//Demo2.php
Class Demo2
{
    public function getName()
    {
        return "名字是xxx
"; } } //正常情况下,我们是需要先实例demo1然后在demo1的构造函数内传入demo2的 //实例,这样的耦合度太高,不宜于第二次扩展 //一般情况下的手法 //直接在new Demo1时就把Demo2给new出来并传入进去 $demo = new Demo1(new Demo2()); echo $demo->Name(); //输出名字是xxx //通过Ioc容器实现 Class Container { //存储当前类的实例 private static $instance; //设置类不能直接new private function __construct(){} //禁止复制当前类 private function __clone(){} //获取当前类的实例 public static function _ins() { //判断成员变量是否存储实例 if(empty(self::$instance)) { //如果没有则存储并返回实例 self::$instance = new static(); return self::$instance; } //如果存储则直接返回 return self::$instance; } //成员变量register存储类的实例或类的描述 private $register = []; //通过魔术方法__set和__get实现 //设置未定义的成员变量时,会经过__set public function __set($key,$Cvalue) { //判断是否已经存储 if(array_key_exists($key,$this->register)) { throw new Exception("错误,已存在这一的一个类"); } $this->register[$key] = $Cvalue; } //访问未定义的成员变量 public function __get($key) { //通过build动态的去获取到类的实例 return $this->build($this->register[$key]); } //自动绑定,自动解析 public function build($ClassName) { //如果是匿名函数则直接返回执行后的结果 if ($ClassName instanceof Closure) { return $ClassName($this); } //通过反射获取到类的内部结构 $reflector = new ReflectionClass($ClassName); //判断类能不能实例化,排除掉抽象类和接口 if(!$reflector->isInstantiable()) { throw new Exception("对象不能实例化"); } //获取到类的构造函数参数 $constructor = $reflector->getConstructor(); //判断构造参数是否没有定义,如果没有,则直接返回类实例 if(empty($constructor)) { return new $ClassName(); } //获取到构造函数内的参数 $params = $constructor->getParameters(); //递归的去调用方法解析并构造参数 $dependencies = $this->getDependencies($params); //创建类的实例 return $reflector->newInstanceArgs($dependencies); } //解析参数 public function getDependencies($parameters) { //存储解析后的参数 $dependencies = []; /** foreach循环获取参数,如果是变量并有默认值就直接返回默认值,如果没有 */ foreach ($parameters as $parameter) { /** 通过反射获取到参数的类名,如果没有。。则直接返回默认值*/ $dependency = $parameter->getClass(); if (is_null($dependency)) { // 是变量,有默认值则设置默认值 $dependencies[] = $this->resolveNonClass($parameter); } else { // 是一个类,递归解析 $dependencies[] = $this->build($dependency->name); } } return $dependencies; } public function resolveNonClass($parameter) { // 有默认值则返回默认值 if ($parameter->isDefaultValueAvailable()) { return $parameter->getDefaultValue(); } //没有默认值就发出警告 throw new Exception('参数没又默认值'); } } //通过Ioc容器获取的 //实例化容器 $app = Container::_ins(); //直接依赖注入 $app->demo1 = 'Demo1'; $demo1 = $app->demo1; //输出名字是xxx echo $demo1->Name();

 参考资料:

  • https://blog.csdn.net/dream_successor/article/details/79078905
  • https://blog.csdn.net/a8228560/article/details/79805195

你可能感兴趣的:(php,php)