由于laravel中的Ioc还考虑了参数为字符串,参数有默认值等众多情况,所以总体看起来比较复杂。
但总之,其目的是为了解决不同类之间的依赖关系。当然工厂方法某种程度上也能解决这个问题,只是,Ioc来的更优雅。
这里提供一个删节版
<?php
/**
*
*/
class Container
{
protected $bindings = [];
public function bind($abstract, $concrete)
{
$this->bindings[$abstract]['concrete'] = $concrete;
}
public function make($abstract)
{
$concrete = $this->getConcrete($abstract);
return $this->build($abstract, $concrete);
}
public function getConcrete($abstract)
{
if(isset($this->bindings[$abstract])) {
return $this->bindings[$abstract]['concrete'];
}
}
public function build($abstract, $concrete)
{
$reflector = new ReflectionClass($concrete);
if(! $reflector->isInstantiable()) {
return '无法实例化';
}
$constructor = $reflector->getConstructor();
if(is_null($constructor)) {
return new $concrete;
}
$parameters = $constructor->getParameters();
$instances = $this->getDependencies($abstract, $parameters);
return $reflector->newInstanceArgs($instances);
}
public function getDependencies($abstract, $parameters)
{
$dependencies = [];
foreach ($parameters as $parameter) {
$dependency = $parameter->getClass();
if(is_null($dependency)) {
$dependencies[] = null;
}
$dependencies[] = $this->make($dependency->name);
}
return $dependencies;
}
}
/**
*
*/
abstract class Tool
{
abstract public function go();
}
/**
*
*/
class Train extends Tool
{
public function go()
{
echo "method go froom class Train";
}
}
/**
*
*/
class Tour
{
protected $tool;
function __construct(Tool $tool)
{
$this->tool = $tool;
}
public function visit()
{
$this->tool->go();
}
}
$container = new Container();
$container->bind('Tool', 'Train');
$container->bind('tour', 'Tour');
$tour = $container->make('tour');
$tour->visit();
输出:method go froom class Train
大功告成,哈哈
当然啦,这里的删节版只是便于理解Ioc的运行原理,并没有对每种情况都考虑周全,比如,若构造函数中需要传入的参数并不是对象,只是单纯的字符串,就会接收到null,还有不支持单例模式等问题。