Laravel简单版IOC服务容器学习笔记
内容来自 - 《Laravel框架关键技术解析》
控制反转:将组件(类)间的依赖关系从程序内部提到外部容器(IOC服务容器)来管理;
依赖注入:将组件(类)的依赖通过外部以参数或其他形式来注入;
控制反转和依赖注入本质上指的都是一个意思;
<?php
//简化版服务容器
class Container
{
protected $bindings = [];
//绑定接口和生成相应实例的回调函数
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)
{
return function ($c) use ($abstract, $concrete) {
$method = ($abstract == $concrete) ? 'build' : 'make';
return $c->$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 isBuildable($concrete, $abstract)
{
return $concrete === $abstract || $concrete instanceof Closure;
}
//获取绑定的回调函数
protected function getConcrete($abstract)
{
if (!isset($this->bindings[$abstract])) {
return $abstract;
}
return $this->bindings[$abstract]['concrete'];
}
//实例化对象
public function build($concrete)
{
if ($concrete instanceof Closure) {
return $concrete($this);
}
$reflector = new ReflectionClass($concrete);
if (!$reflector->isInstantiable()) {
echo "Target [$concrete] is not instantiable";
}
$constructor = $reflector->getConstructor();
if (is_null($constructor)) {
//没有构造函数直接实例化
return new $concrete;
}
$dependencies = $constructor->getParameters();
$instances = $this->getDependencies($dependencies);
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 $dependencies;
}
protected function resolveClass(ReflectionParameter $parameter)
{
return $this->make($parameter->getClass()->name);
}
}
使用例子展示
<?php
//使用控制反转,依赖注入解决类之间的依赖
//旅游场景说明
interface Visit
{
public function go();
}
class Leg implements Visit
{
public function go()
{
echo 'walk to Beijing' . PHP_EOL;
}
}
class Car implements Visit
{
public function go()
{
echo 'drive car to Beijing' . PHP_EOL;
}
}
class Train implements Visit
{
public function go()
{
echo 'go to Beijing by train' . PHP_EOL;
}
}
//旅游者
class Traveller
{
protected $trafficTool;
public function __construct(Visit $trafficTool)
{
// $this->trafficTool = new Leg();
//从内部实例化依赖转变为通过外部注入依赖的方式
$this->trafficTool = $trafficTool;
}
public function visit()
{
$this->trafficTool->go();
}
}
//客户端调用 依赖注入方式
// $visit = new Car();
// $traveller = new Traveller($visit);
// $traveller->visit();
//使用服务容器来实现依赖注入
require_once './Container.php';
$container = new Container();
$container->bind('Visit', 'Leg');
$container->bind('traveller', 'Traveller');
$traveller = $container->make('traveller');
$traveller->visit();