欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

通过源码解析Laravel的依赖注入

程序员文章站 2022-05-15 07:57:16
前言 众所周知,php的框架数不胜数,近几年,一个以优雅著称的框架,渐渐被国内phper所知道,并且开始使用,但是larave有一个很明显的缺点就是,他的文档内容少的可怜...

前言

众所周知,php的框架数不胜数,近几年,一个以优雅著称的框架,渐渐被国内phper所知道,并且开始使用,但是larave有一个很明显的缺点就是,他的文档内容少的可怜。

本文将给大家详细介绍关于laravel依赖注入的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。

在 laravel 的控制器的构造方法或者成员方法,都可以通过类型约束的方式使用依赖注入,如:

public function store(request $request)
{
 //todo
}

这里 $request 参数就使用了,request 是一个类:\illuminate\http\request,表示参数必须是这个类或子类。

本文通过分析 laravel 的源码,看为什么方法中不需要传入实例就可以直接使用 request 呢?只是框架自动帮我们实例化并传参了。

1.路由定义

从源头开始看起,在路由定义文件中定义了这么一个路由:

route::resource('/role', 'admin\rolecontroller');

这是一个资源型的路由,laravel 会自动生成增删改查的路由入口。

通过源码解析Laravel的依赖注入

本文开头的 store 方法就是一个控制器的方法,图中可见路由定义的 action 也是:app\http\controllers\admin\rolecontroller@store

路由方法解析

根据路由定义找到控制器和方法,执行具体的方法在 dispatch 方法中实现。

(文件:vendor/laravel/framework/src/illuminate/routing/controllerdispatcher.php)

public function dispatch(route $route, $controller, $method)
{
 $parameters = $this->resolveclassmethoddependencies(
  $route->parameterswithoutnulls(), $controller, $method
 );
 
 if (method_exists($controller, 'callaction')) {
  return $controller->callaction($method, $parameters);
 }
 
 return $controller->{$method}(...array_values($parameters));
}

首先 resolveclassmethoddependencies 方法,“顾名思义”是根据类的方法参数获取依赖对象,然后再调用类的方法并把对象参数注入。

如果有多个依赖对象,也会 foreach 依次解析出来作为参数注入。

获取依赖对象示例的代码:

protected function resolveclassmethoddependencies(array $parameters, $instance, $method)
{
 if (! method_exists($instance, $method)) {
  return $parameters;
 }
 
 return $this->resolvemethoddependencies(
  $parameters, new reflectionmethod($instance, $method)
 );
}

这里重点就是用到了 php 的反射,注意 relectionmethod 方法,它获取到类的方法参数列表,可以知道参数的类型约束,参数名称等等。

这里的 $instance 参数就是 rolecontroller 控制器类,$method 参数就是方法名称 strore.

2.获取依赖对象的示例

从方法的参数中获取了依赖对象的约束类型,就可以实例化这个依赖的对象。

protected function transformdependency(reflectionparameter $parameter, $parameters)
{
 $class = $parameter->getclass(); 
 // if the parameter has a type-hinted class, we will check to see if it is already in
 // the list of parameters. if it is we will just skip it as it is probably a model
 // binding and we do not want to mess with those; otherwise, we resolve it here.
 if ($class && ! $this->alreadyinparameters($class->name, $parameters)) {
  return $parameter->isdefaultvalueavailable()
   ? $parameter->getdefaultvalue()
   : $this->container->make($class->name);
 }
}

根据类名从容器中获取对象,这个绑定对象实例的过程在服务提供者中先定义和了。

然后把实例化的对象传入到 store 方法中,就可以使用依赖的对象了。

3.关于 php 反射

举个使用 reflectionmethod 的例子。

class demo
{
 private $request;
 public function store(request $request)
 {
 }
}

打印出 new reflectionmethod(demo::class, ‘store') 的内容如图:

通过源码解析Laravel的依赖注入

可以得出这个方法的参数列表,参数的约束类型,如 typehint,illuminate\http\request.

根据类名可以从容器中获取一开始通过服务提供者绑定的实例。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。