提到laravel框架,我的脑海中最先浮现的是什么呢?那一定是,依赖注入、控制反转。作为后来居上的框架,laravel能取得如此的成绩,优秀的思想也贡献了很大一部分力量。
什么是Container?
定义:
那么在提到依赖注入之前我们就不得不先说一说一切的根本:容器Container。所谓容器,听名字就知道,是一个仓库,装东西用的,所以,container所有的功能,都围绕一个主题:管理类。
工作流程:
首先,生成一个数组绑定列表,用自定义名称作为主键,然后键值是闭包(输入的可能是闭包或者实体类,但是,在存储的时候,都统一转化成了闭包存储)。 其次,根据绑定列表,生成对应的类的实例,供用户使用,调用的时候,发现如果已经生成,不需要重新生成使用,实际上,Container就是类的一个仓库,以及缓存。 在laravel中Container的实现类为\Illuminate\Container\Container,该类提供了多个操作类的方法。 Container位于…/vendor/laravel/framework/src/Illuminate/Container/Container.php中,接下来我们来看下其常用方法(因版本不同,源码可能略有偏差,如果问题,欢迎留言指正!!!)
别名函数:
public function alias($abstract, $alias)
{
$this->aliases[$alias] = $abstract;
$this->abstractAliases[$abstract][] = $alias;
}
public function getAlias($abstract)
{
if (! isset($this->aliases[$abstract])) {
return $abstract;
}
if ($this->aliases[$abstract] === $abstract) {
throw new LogicException("[{$abstract}] is aliased to itself.");
}
return $this->getAlias($this->aliases[$abstract]);
}
public function isAlias($name)
{
return isset($this->aliases[$name]);
}
isBuildable函数:
用来判断指定类型是否可构建(实例化)。满足二者之一则可实例化:实际类型是Closure或者实际类型与抽象类型名称相同(其实就是普通的类名称,非抽象类和接口)
protected function isBuildable($concrete, $abstract)
{
return $concrete === $abstract || $concrete instanceof Closure;
}
容器绑定函数:bind、singleton
singleton是单例的,是bind函数share的一个应用。
public function bind($abstract, $concrete = null, $shared = false)
{
$this->dropStaleInstances($abstract);
if (is_null($concrete)) {
$concrete = $abstract;
}
if (! $concrete instanceof Closure) {
$concrete = $this->getClosure($abstract, $concrete);
}
$this->bindings[$abstract] = compact('concrete', 'shared');
if ($this->resolved($abstract)) {
$this->rebound($abstract);
}
}
实例化函数:make
make函数会自动完成类依赖的注入。
public function make($abstract, array $parameters = [])
{
$abstract = $this->getAlias($this->normalize($abstract));
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
}
$concrete = $this->getConcrete($abstract);
if ($this->isBuildable($concrete, $abstract)) {
$object = $this->build($concrete, $parameters);
} else {
$object = $this->make($concrete, $parameters);
}
foreach ($this->getExtenders($abstract) as $extender) {
$object = $extender($object, $this);
}
if ($this->isShared($abstract)) {
$this->instances[$abstract] = $object;
}
$this->fireResolvingCallbacks($abstract, $object);
$this->resolved[$abstract] = true;
return $object;
}
实例化函数:build
用来实例化指定类型的对象,等同于直接new 对象,只不过这个操作有容器来完成
public function build($concrete, array $parameters = [])
{
if ($concrete instanceof Closure) {
return $concrete($this, $parameters);
}
$reflector = new ReflectionClass($concrete);
if (! $reflector->isInstantiable()) {
if (! empty($this->buildStack)) {
$previous = implode(', ', $this->buildStack);
$message = "Target [$concrete] is not instantiable while building [$previous].";
} else {
$message = "Target [$concrete] is not instantiable.";
}
throw new BindingResolutionException($message);
}
$this->buildStack[] = $concrete;
$constructor = $reflector->getConstructor();
if (is_null($constructor)) {
array_pop($this->buildStack);
return new $concrete;
}
$dependencies = $constructor->getParameters();
$parameters = $this->keyParametersByArgument(
$dependencies, $parameters
);
$instances = $this->getDependencies(
$dependencies, $parameters
);
array_pop($this->buildStack);
return $reflector->newInstanceArgs($instances);
}
接下来我们通过一些小例子来加深理解。
abstract class Animal
{
abstract public function run();
}
class Fish extends Animal
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function run()
{
echo 'Fish run';
}
}
class Pig extends Animal
{
protected $name;
public function __construct($name)
{
$this->name = $name;
}
public function getName()
{
return $this->name;
}
public function run()
{
echo 'Pig run';
}
}
class People
{
protected $food;
public function __construct(\Animal $food)
{
$this->food = $food;
}
public function eat()
{
$this->food->run();
}
}
$object2 = new Fish('panda2');
echo $object2->getName();
$container = new \Illuminate\Container\Container();
$object = $container->build('Fish', ['panda']);
echo $object->getName();
$container->bind('Animal', 'Fish');
$object3 = $container->make('Animal', ['goldfish']);
echo $object3->run();
$container->flush();
$container->singleton('Animal', 'Fish');
$object4 = $container->make('Animal', ['goldfish']);
$object5 = $container->make('Animal', ['goldfish']);
var_dump($object4 === $object5);
$container->flush();
$container->bind('Animal', 'Fish');
$people = $container->make('people');
$people->eat();
小结
本章节我们学历了laravel的容器及其常用的相关函数,希望对大家阅读源码有帮助,后续我们将继续对laravel源码进行学习,有兴趣的动动小手点个关注吧,感谢观看!
|