DI:Dependency Injection,依赖注入,是指在程序运行期间,如果依赖于其它的对象时,不在
代码中创建该类对象,而是由外部容器创建后再传递给程序(即由容器动态的将某些依赖关系注入到组件中)
IoC:Inversion of Control,控制反转,是面向对象编程中的一种设计原则,它的目的是帮助我们设计出松耦合、更灵活、易扩展的程序代码。IoC意味着把你设计好的对象交给容器控制,而不是传统的由程序对象内部直接控制。IoC容器管理所有轻量级的扩展组件对象,提供 包括组件的生命周期管理、配置和组装等服务。如果把程序代码对其它依赖对象的控制权(主动实例化和调用)看作正向控制,那么这种把依赖对象的控制权交给外部容器,然后向IoC容器来申请这些资源,则即为控制反转。
IoC中最常见的方式是“依赖注入”(Dependency Injection),还有一种方式叫“依赖查找”(Dependency Lookup)。
对IoC容器的实践:
<?php class IoC { // 注册服务集合 public $services = []; /** * 注册服务 * @param $class * @param $generator */ public function bind($class, $generator) { if ($generator instanceof Closure) { $this->services[$class] = $generator; } else { $this->services[$class] = function () use ($generator) { return $this->build($generator); }; } } /** * 获取服务对象实例 * @param $class * @return object|null */ public function make($class) { if (isset($this->services[$class])) { $new = $this->services[$class]; } else { $new = function () use ($class) { return $this->build($class); }; } return $new(); } /** * 通过反射构建服务实现 * @param $class * @param array $params * @return object|null */ public function build($class, $params = []) { try { $reflection = new ReflectionClass($class); // 判断类是否可实例化 if (!$reflection->isInstantiable()) { return null; } // 获取类构造器 $constructor = $reflection->getConstructor(); // 判断构造方法是否为null,为null时直接返回实例 if (is_null($constructor)) { return new $class; } // 获取构造器参数列表 $parameters = $constructor->getParameters(); // 判断构造方法参数列表是否为空,为空时直接返回实例 if (empty($parameters)) { return new $class; } $dependencies = []; // 检查注入的依赖 foreach ($parameters as $parameter) { // 获取参数声明的类型 $dependencyClass = $parameter->getClass(); if (is_null($dependencyClass)) { $dependencies[] = null; } else { $dependencies[] = $this->make($dependencyClass->getName()); } } return $reflection->newInstanceArgs($dependencies); } catch (\Exception $e) { } } } class User { public $userAddress; public function __construct(UserAddress $userAddress) { // 主动实例化依赖对象 // $this->userAddress = new UserAddress(); // 外部注入 $this->userAddress = $userAddress; } public function showUserAddress() { $this->userAddress->getUserAddress(); } } class UserAddress { public function getUserAddress() { echo 'shanghai'; } } $ioc = new IoC(); $ioc->bind('User', 'User'); $user = $ioc->make('User'); $user->showUserAddress();
基于IoC,我们可以继续扩展,增加单例、上下文绑定等设计。