Laravel依赖注入
Laravel容器是用于管理类依赖和注入类依赖的一个容器,所运用的思想是依赖注入和控制翻转,下面先来看一下依赖注入的简单例子
依赖注入的概念详细介绍 blog.csdn.net/sinat_21843…
class Ioc {
protected $ioc;
public function __construct(IocResponse $ioc)
{
$this->ioc = $ioc;
}
//执行ioc容器的方法
public function get(){
return $this->ioc->get();
}
}
使用了依赖注入之后,我们将类的实例化进行解耦
下面我们来看看如何非常简单的获取到构造方法中的类实例化,这里我们需要使用到PHP的反射
//A类
class A
{
public function __construct()
{
}
public function show(){
echo "AAA";
}
}
//B类
class B
{
public function __construct(A $a)
{
}
public function show() {
echo "BBB";
}
}
//C类
class C
{
protected $a;
protected $b;
public function __construct(A $a, B $b)
{
$this->a = $a;
$this->b = $b;
}
public function show(){
$this->a->show();
$this->b->show();
}
}
//获取类的实例
function make($name)
{
//使用类的反射获取到类的实例
$ref = new ReflectionClass($name);
//获取到b的构造函数
$cons = $ref->getConstructor();
//获取构造函数中的参数
$arguments = $cons->getParameters();
//获取实例类
$dep = dependencies($arguments);
//进行实例化
return $ref->newInstanceArgs($dep);
}
//解析类的参数
function dependencies($arg)
{
$make = [];
foreach ($arg as $k => $param) {
//获取它的类
$dep = $param->getClass();
//如果不是空的话
if (!is_null($dep)) {
//会存在多层的解析,例如上面反射C 得到A B ,B 需要A
$make [] = make($param->getClass()->name);
}else{
//如果是空的话 存在默认值的话 则放入数组中
if($param->isDefaultValueAvailable()) {
$make[] = $param->getDefaultValue();
}
}
}
return $make;
}
$c = make("C");
$c->show();
通过以上简单的反射,我们粗略的实现了类的依赖注入,接下来我们看看Larave是如何实现依赖注入的
//Laravel的依赖注入核心代码
//laravel/framework/src/Illuminate/Container/Container.php
public function build($concrete)
{
// If the concrete type is actually a Closure, we will just execute it and
// hand back the results of the functions, which allows functions to be
// used as resolvers for more fine-tuned resolution of these objects.
//如果是回调函数的话,直接执行
if ($concrete instanceof Closure) {
return $concrete($this, $this->getLastParameterOverride());
}
//这里就开始使用反射
$reflector = new ReflectionClass($concrete);
// If the type is not instantiable, the developer is attempting to resolve
// an abstract type such as an Interface of Abstract Class and there is
// no binding registered for the abstractions so we need to bail out.
//判断类是否可以实例化,不可以实例化的话,直接抛出异常
if (! $reflector->isInstantiable()) {
return $this->notInstantiable($concrete);
}
//放入队列中
$this->buildStack[] = $concrete;
//获取构造方法
$constructor = $reflector->getConstructor();
// If there are no constructors, that means there are no dependencies then
// we can just resolve the instances of the objects right away, without
// resolving any other types or dependencies out of these containers.
//如果不存在构造方法的话,弹出队列,直接实例化
if (is_null($constructor)) {
array_pop($this->buildStack);
return new $concrete;
}
//获取参数
$dependencies = $constructor->getParameters();
// Once we have all the constructor's parameters we can create each of the
// dependency instances and then use the reflection instances to make a
// new instance of this class, injecting the created dependencies in.
//调用方法解析参数
$instances = $this->resolveDependencies(
$dependencies
);
//解析完成 弹出队列
array_pop($this->buildStack);
//进行实例化操作
return $reflector->newInstanceArgs($instances);
}
protected function resolveDependencies(array $dependencies)
{
$results = [];
foreach ($dependencies as $dependency) {
// If this dependency has a override for this particular build we will use
// that instead as the value. Otherwise, we will continue with this run
// of resolutions and let reflection attempt to determine the result.
if ($this->hasParameterOverride($dependency)) {
$results[] = $this->getParameterOverride($dependency);
continue;
}
// If the class is null, it means the dependency is a string or some other
// primitive type which we can not resolve since it is not a class and
// we will just bomb out with an error since we have no-where to go.
//如果不是类的话,resolvePrimitive处理
$results[] = is_null($dependency->getClass())
? $this->resolvePrimitive($dependency)
: $this->resolveClass($dependency);
}
return $results;
}
protected function resolveClass(ReflectionParameter $parameter)
{
//再次进行处理
try {
return $this->make($parameter->getClass()->name);
}
// If we can not resolve the class instance, we will check to see if the value
// is optional, and if it is we will return the optional parameter value as
// the value of the dependency, similarly to how we do this with scalars.
catch (BindingResolutionException $e) {
if ($parameter->isOptional()) {
return $parameter->getDefaultValue();
}
throw $e;
}
}
以上我们对Laravel的依赖注入的核心代码进行了注释说明,可以发现其实跟我们自己的思想大致相同,都是使用PHP的反射,获取到类的属性等