依赖注入(DI)
依赖注入(DI)是一种设计模式,通过在对象创建时将其所依赖的其他对象(依赖)作为参数传递给对象,从而实现对象之间的解耦。简而言之,对象不再负责自己的依赖关系的创建和管理,而是由外部的调用者或容器负责将依赖注入到对象中。这样可以使得对象更加灵活、可测试和可扩展。
控制反转(IoC)
控制反转(IoC)是一种软件设计原则,它将程序的控制权从原本由程序员手动控制的方式转移到外部容器或框架中。控制反转的核心思想是反转了对象的创建和管理控制权,由外部容器负责创建和管理对象,而不是由对象自身来创建和管理依赖关系。依赖注入就是控制反转的一种具体实现方式。
通过依赖注入和控制反转,可以带来以下好处:
- 解耦:通过依赖注入,对象不再直接依赖于具体的实现类,而是依赖于抽象接口或基类。这样可以降低类之间的耦合度,使得代码更加灵活和可维护。
- 可测试性:通过依赖注入,可以方便地替换依赖对象,从而实现对对象的单元测试。可以使用模拟对象或桩对象来替代真实的依赖,使得测试更加简单和可控。
- 可扩展性:通过依赖注入,可以方便地在不修改现有代码的情况下,替换、添加或移除依赖对象。这样可以提高代码的可扩展性,使得系统更容易适应变化和需求的变更。
反射 Reflection
PHP反射(Reflection)是PHP提供的一种强大的内置功能,允许运行时获取类、函数、方法、属性等的信息,并进行操作和修改。通过PHP反射,可以在不了解类或方法内部结构的情况下,动态地获取和操作它们的信息。
PHP反射提供了以下主要类:
- ReflectionClass:用于获取类的信息,如类名、父类、接口、属性、方法等。可以通过ReflectionClass实例化一个类,并调用其方法。
- ReflectionMethod:用于获取方法的信息,如方法名、参数、返回值、访问修饰符等。可以通过ReflectionMethod调用方法,并传递相应的参数。
- ReflectionFunction:用于获取函数的信息,类似于ReflectionMethod,但用于非类方法。
- ReflectionProperty:用于获取属性的信息,如属性名、访问修饰符、默认值等。可以通过ReflectionProperty获取和设置属性的值。
通过这些反射类,可以实现以下功能:
- 动态调用方法和函数:使用ReflectionMethod和ReflectionFunction,可以在运行时动态调用方法和函数,而不需要直接知道它们的名称或参数。
- 获取类的结构信息:使用ReflectionClass,可以获取类的名称、父类、接口、属性、方法等信息。这对于实现自动化代码生成、文档生成等工具非常有用。
- 动态创建对象:ReflectionClass提供了实例化类的功能,可以在运行时动态创建对象。
- 修改类和对象:使用ReflectionClass和ReflectionProperty,可以修改类的属性和方法的访问修饰符,甚至替换或删除类中的方法。
PHP反射功能非常强大,可以在运行时分析和操作代码,使得代码更加灵活和可扩展。
详细的文档请参考官网:
https://www.php.net/manual/zh/book.reflection.php
ioc容器
IOC容器就是具有依赖注入功能的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需直接在代码中new相关的对象,应用程序由IOC容器进行组装。
下面是利用反射来实现的一个简单ioc容器的demo
<?php
class DI
{
protected static $data = [];
public function __set($k, $v)
{
self::$data[$k] = $v;
}
public function __get($k)
{
return $this->bulid(self::$data[$k]);
}
// 获取实例
public function bulid($className)
{
// 如果是匿名函数,直接执行,并返回结果
if ($className instanceof Closure) {
return $className($this);
}
// 已经是实例化对象的话,直接返回
if(is_object($className)) {
return $className;
}
// 如果是类的话,使用反射加载
$ref = new ReflectionClass($className);
// 监测类是否可实例化
if (!$ref->isInstantiable()) {
throw new Exception('class' . $className . ' not find');
}
// 获取构造函数
$construtor = $ref->getConstructor();
// 无构造函数,直接实例化返回
if (is_null($construtor)) {
return new $className;
}
// 获取构造函数参数
$params = $construtor->getParameters();
// 解析构造函数
$dependencies = $this->getDependecies($params);
// 创建新实例
return $ref->newInstanceArgs($dependencies);
}
// 分析参数,如果参数中出现依赖类,递归实例化
public function getDependecies($params)
{
$data = [];
foreach($params as $param)
{
$tmp = $param->getClass();
if (is_null($tmp)) {
$data[] = $this->setDefault($param);
} else {
$data[] = $this->bulid($tmp->name);
}
}
return $data;
}
// 设置默认值
public function setDefault($param)
{
if ($param->isDefaultValueAvailable()) {
return $param->getDefaultValue();
}
throw new Exception('no default value!');
}
}
class Demo
{
public function __construct(Calc $calc)
{
echo $calc->plus(1, 2);
}
}
class Calc
{
public function plus($a, $b)
{
return $a + $b;
}
public function minus($a, $b)
{
return $a - $b;
}
}
$di = new DI();
$di->calc = 'Calc';
$di->demo = 'Demo';
$di->demo;//输出结果为3