文章最后有一个简单的容器实现示例和使用示例,可以参考理解,对应的github源码:GitHub源码
一个仿照yii2框架容器实现的代码示例:GitHub源码 ,其中register方法对应set方法,resolve方法对应set方法
或 GitHub源码
一个摘自laravel框架容器实现和使用示例:GitHub源码
psr-11容器GitHub地址规范
1.容器类一般有get和set方法。
使用容器,一般先注册:
例如把A(具体类)注册到AInterface(接口或抽象类)上
$container->set(‘AInterface’, ‘A’);
然后通过容器的get方法获取对象
$a = $container->get('AInterface');
2.当然你也可以引入别名的概念,set时传入参数机制,get时传入参数机制,根据上下文实例化不同对象的机制等等,这些都是增强功能,核心还是set和get方法
3.set方法实现
一般有一个defines数组保存AInterface 和A之间的注册关系,
set时,直接将关系保存到defines数组
4.get方法实现
1) 有一个数组instances保存已经实例化的对象
如果这里有已经实例化的,直接取出返回
2) 在defines数组中取出和AInterface相应的类A.
3) 使用类反射获取类A的构造方法和构造方法的签名:
ReflectionClass::getConstructor()获取构造方法对象
ReflectionMethod::getParameters()获取函数签名
4) 如果签名中有对象,则通过容器的get方法获取
如果有默认参数,则使用默认参数
如果传递的有参数,则覆盖原有值
5) 最后通过ReflectionClass::newInstanceArgs()方法获取类的实例化对象
5.这样在使用类时,我们只要通过容器get它的接口或抽象,容器会自动返回绑定的具体类的实例。这就实现了依赖接口或抽象,而不依赖具体类,达到可依赖倒转的目的。
容器实现示例:
class SimpleContainer
{
private $defines = [];
private $instances = [];
public function set($abstract, $concrete)
{
$this->defines[$abstract] = $concrete;
}
public function get($abstract)
{
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
}
$object = null;
if (isset($this->defines[$abstract])) {
$concrete = $this->defines[$abstract];
$object = $this->build($concrete);
} else {
$object = $this->build($abstract);
}
$this->instances[$abstract] = $object;
return $object;
}
private function build($concrete)
{
$reflector = new ReflectionClass($concrete);
//如果不能实例化,抛出异常
if (!$reflector->isInstantiable()) {
throw new Exception('class ['.$concrete.'] can not be instantiated!');
}
//获取构造函数方法反射对象
$constructor = $reflector->getConstructor();
//类不存在构造函数,直接实例化
if (is_null($constructor)) {
return new $concrete;
}
//给每个签名参数赋值,如果参数是对象则实例化,如果有默认值则赋给默认值
foreach ($constructor->getParameters() as $param) {
if ($param->isDefaultValueAvailable()) {
$dependencies[] = $param->getDefaultValue();
} else {
$dependClass = $param->getClass();
$isClass = !is_null($dependClass) ? true : false;
$dependencies[] = $isClass ? $this->get($dependClass->getName()) : null;
}
}
//实例化对象
return $reflector->newInstanceArgs($dependencies);
}
}
容器使用示例:
require_once 'SimpleContainer.php';
interface AInterface
{
public function run();
}
class A implements AInterface
{
public function run()
{
return 'I am A!';
}
}
class B
{
private $example;
public function __construct(AInterface $example)
{
$this->example = $example;
}
public function run()
{
$str = $this->example->run();
return '<<<< '.$str.' >>>>';
}
}
$container = new SimpleContainer();
//示例1
$container->set('AInterface', 'A');
$a = $container->get('AInterface');
var_dump($a->run());
//示例2
$b = $container->get('B');
var_dump($b->run());