Laravel Container 中 为什么要用 $concrete === $abstract 来判断是 build 还是 make?
<?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] = [
'concrete' => $concrete,
'shared' => $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)) {
$obj = $this->build($concrete);
} else {
$obj = $this->make($concrete);
}
return $obj;
}
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 $message = "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 (array)$dependencies;
}
protected function resolveClass(ReflectionParameter $parameter)
{
return $this->make($parameter->getClass()->name);
}
}
interface Visit
{
public function go();
}
class Leg implements Visit
{
public function go()
{
echo 'walk to Tibet!';
}
}
class Car implements Visit
{
public function go()
{
echo 'drive to Tibet!';
}
}
class Train implements Visit
{
public function go()
{
echo 'go to Tibet by Train!';
}
}
class Traveller
{
protected $trafficTool;
public function __construct(Visit $trafficTool)
{
$this->trafficTool = $trafficTool;
}
public function visitTibet()
{
$this->trafficTool->go();
}
}
$app = new Container();
$app->bind('Visit', 'Train');
$app->bind('traveller', "Traveller");
$tra = $app->make('traveller');
$tra->visitTibet();
在getClosure 和 isBuildable 中 为什么要用 $concrete === $abstract 来判断是build还是make。不是理解的很透彻。 像这样的容器是怎么一步步设计构建出来的
bind的时候,如果concrete为null的话,默认concrete = abstract。而且build是make的其中一个环节,如果make是需要调用回调或者需要new一个类的时候就使用build,如果在instances里就直接返回了