由于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,还有不支持单例模式等问题。