一个简单的容器实现。
服务容器的目的是解决组件之间的依赖关系,降低耦合。
在系统运行过程中动态地为系统提供各种服务。
<?php
/**
* 一个容器类
*/
class Container
{
protected $bindings = []; // 绑定接口和生成实例的回调函数
/**
* 向容器中添加一个绑定
* abstract 服务名称
* concrete \Closure|string(命名空间+类名称)|null 服务所对应的具体内容
* shared这个参数用于标记绑定的服务是否为单例,但本demo并没有实现对单例服务的处理。
*/
public function bind($abstract, $concrete = null, $shared = false)
{
if (!$concrete instanceof Closure) {
// 如果提供的参数不是回调函数,则产生默认的回调函数
$concrete = $this->getClosure($abstract, $concrete);
}
// 将绑定关系存到数组中
$this->bindings[$abstract] = compact('concrete', 'shared');
}
protected function getClosure($abstract, $concrete)
{
// $app一般为IoC容器对象,在调用回调生成实例时提供
// 即bind函数中的 $concrete($this)
return function ($app) use ($abstract, $concrete) {
$method = ($abstract == $concrete) ? 'build' : 'make';
//调用容器的make或build方法生成实例
return $app->$method($concrete);
};
}
// 从容器中解析服务
public function make($abstract)
{
// 从绑定的数组中获取包含服务的回调函数
$concrete = $this->getConcrete($abstract);
if ($this->isBuildable($concrete, $abstract)) {
$object = $this->build($concrete);
} else {
$object = $this->make($concrete);
}
return $object;
}
// 获取绑定的回调函数
protected function getConcrete($abstract)
{
if ( !isset($this->bindings[$abstract])) {
return $abstract;
}
return $this->bindings[$abstract]['concrete'];
}
// 检测对应绑定是否可build
protected function isBuildable($concrete, $abstract)
{
return $concrete === $abstract || $concrete instanceof Closure;
}
// 实例化对象
public function build($concrete)
{
// 如果绑定的内容是个闭包则返回闭包的执行结果
if ($concrete instanceof Closure) {
return $concrete($this);
}
// 此时$concrete就是个带命名空间的字符串,例如'\CCTT',然后通过PHP的反射机制,获取类的信息
$reflector = new ReflectionClass($concrete);
// 检测类是否可被实例化
if (!$reflector->isInstantiable()) {
echo $message = "Target [$concrete] is not instantiable";
}
// 获取类的构造函数
$constructor = $reflector->getConstructor();
// 如果没有构造函数则直接new该类并return
if (is_null($constructor)) {
return new $concrete;
}
// 获取构造函数的参数(依赖关系)
$dependencies = $constructor->getParameters();
// 获取构造函数要传的参(解决依赖注入,获取构造函数中依赖注入的参数的实例)
$instances = $this->getDependencies($dependencies);
// 带参数new该类并return
return $reflector->newInstanceArgs($instances);
}
// 解决通过反射机制实例化对象的依赖
protected function getDependencies($parameters)
{
$dependencies = [];
foreach ($parameters as $parameter) {
$dependency = $parameter->getClass();
if (is_null($dependency)) {
$dependencies[] = NULL; // 对非依赖注入参数这里暂不做处理
} else {
// 获取依赖注入的实例
$dependencies[] = $this->resolveClass($parameter);
}
}
return (array) $dependencies;
}
// 获取依赖注入的实例
protected function resolveClass(ReflectionParameter $parameter)
{
// 实例化每个依赖,并返回
return $this->make($parameter->getClass()->name);
}
}
interface Source
{
public function Stream();
}
class CCTT implements Source
{
public function Stream()
{
echo __CLASS__.' Stream';
}
}
class Qvod
{
protected $source;
public function __construct(Source $source)
{
$this->source = $source;
}
public function play()
{
$this->source->Stream();
}
}
$app = new Container();
$app->bind('Source', 'CCTT');
$app->bind('player', 'Qvod');
$player = $app->make('player');
$player->play();