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,我们可以继续扩展,增加单例、上下文绑定等设计。