前言

通过实现laravel 框架功能,以便深入理解laravel框架的先进思想。

什么是服务容器

服务容器是用来管理类依赖与运行依赖注入的工具。Laravel框架中就是使用服务容器来实现 ** 控制反转 ** 和 ** 依赖注入 **。

什么是控制反转(IoC)和依赖注入(DI)

控制反转(IoC) 就是说把创建对象的** 控制权 **进行转移,以前创建对象的主动权和创建时机是由自己把控的,而现在这种权力转移到第三方,也就是 ** Laravel ** 中的容器。

依赖注入(DI)则是帮助容器实现在运行中动态的为对象提供提依赖的资源。

概念容易不太容易让人理解,举个栗子:

//我们构建一个人的类和一个狗的类
class People
{
public $dog = null; public function __construct()
{
$this->dog = new Dog();
} public function putDog(){
return $this->dog->dogCall();
} } class Dog{
public function dogCall(){
return '汪汪汪';
}
}

这个人在遛狗,突然遇到了死对头,他于是放狗咬人

$people = new People();
$people->putDog();

在这个操作中,people类要执行putDog()这个方法,需要依赖Dog类,一般我们像上面一样,在people中利用构造函数来添加这个Dog依赖。如果使用控制反转 依赖注入则是这个样子

class People
{
public $dog = null; public function __construct(Dog $Dog)
{
$this->dog = $dog;
} public function putDog(){
return $this->dog->dogCall();
} }

People类通过构造参数声明自己需要的 依赖类,由容器自动注入。这样就实现了程序的有效解耦,好处在这就不多说了。

Laravel容器依赖注入的实现

实现原理需要了解的知识点:

闭包(匿名函数):

匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数

反射:PHP 5 以上版本具有完整的反射 API,添加了对类、接口、函数、方法和扩展进行反向工程的能力。 此外,反射 API 提供了方法来取出函数、类和方法中的文档注释

理解了闭包和反射的基本用法我们来看Laravel中是怎么实现容器的,下面代码是我对laravel框架容器部分代码的简化核心版:
lass Container
{
/**
* 容器绑定,用来装提供的实例或者 提供实例的回调函数
* @var array
*/
public $building = []; /**
* 注册一个绑定到容器
*/
public function bind($abstract, $concrete = null, $shared = false)
{
if(is_null($concrete)){
$concrete = $abstract;
} if(!$concrete instanceOf Closure){
$concrete = $this->getClosure($abstract, $concrete);
} $this->building[$abstract] = compact("concrete", "shared");
} //注册一个共享的绑定 单例
public function singleton($abstract, $concrete, $shared = true){
$this->bind($abstract, $concrete, $shared);
} /**
* 默认生成实例的回调闭包
*
* @param $abstract
* @param $concrete
* @return Closure
*/
public 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)){
$object = $this->build($concrete);
}else{
$object = $this->make($concrete);
} return $object;
} /**
* 获取绑定的回调函数
*/
public function getConcrete($abstract)
{
if(! isset($this->building[$abstract])){
return $abstract;
} return $this->building[$abstract]['concrete'];
} /**
* 判断 是否 可以创建服务实体
*/
public function isBuildable($concrete, $abstract)
{
return $concrete === $abstract || $concrete instanceof Closure;
} /**
* 根据实例具体名称实例具体对象
*/
public function build($concrete)
{
if($concrete instanceof Closure){
return $concrete($this);
} //创建反射对象
$reflector = new ReflectionClass($concrete); if( ! $reflector->isInstantiable()){
//抛出异常
throw new \Exception('无法实例化');
} $constructor = $reflector->getConstructor();
if(is_null($constructor)){
return new $concrete;
} $dependencies = $constructor->getParameters();
$instance = $this->getDependencies($dependencies); return $reflector->newInstanceArgs($instance); } //通过反射解决参数依赖
public function getDependencies(array $dependencies)
{
$results = [];
foreach( $dependencies as $dependency ){
$results[] = is_null($dependency->getClass())
?$this->resolvedNonClass($dependency)
:$this->resolvedClass($dependency);
} return $results;
} //解决一个没有类型提示依赖
public function resolvedNonClass(ReflectionParameter $parameter)
{
if($parameter->isDefaultValueAvailable()){
return $parameter->getDefaultValue();
}
throw new \Exception('出错'); } //通过容器解决依赖
public function resolvedClass(ReflectionParameter $parameter)
{
return $this->make($parameter->getClass()->name); } }

容器的工作流程

接着上面遛狗的例子:

//实例化容器类
$app = new Container();
//向容器中填充Dog
$app->bind('Dog','App\Dog');
//填充People
$app->bind('People', 'App\People');
//通过容器实现依赖注入,完成类的实例化;
$people = $app->make('People');
//调用方法
echo $people->putDog();

上面示例中我们先实例化容器类,然后使用bind()方法 绑定接口和 生成相应的实例的闭包函数。然后使用make() 函数生成实例对象,在make()中会调用 isBuildable($concrete, $abstract) 来判断 给定的服务实体($concrete参数)是否可以创建,可以创建 就会调用 build($concrete) 函数 ,build($concrete) 函数会判断传的参数是 是** 闭包 还是 具体类名 **,如果是闭包则直接运行,如果是具体类名的话,则通过反射获取该类的构造函数所需的依赖,完成实例化。

** 重点理解 下面这几个函数中 反射的用法,应该就很好理解了 **

build($concrete)
getDependencies(array $dependencies)
resolvedNonClass(ReflectionParameter $parameter)
resolvedClass(ReflectionParameter $parameter) ``` ## 最后 ##
> IoC 理解起来是有点难度,可能文中描述让你感觉不是很清楚,可以将文中代码 在php中用debug观察 运行状态。
理解了容器的具体实现原理,再去看Laravel中的相关实现,就会感觉豁然开朗。

最新文章

  1. CSS3--背景颜色的渐变效果
  2. Android分辨率适配心得
  3. ural 1106,二分图染色,DFS
  4. Mybatis 实现传入参数是表名
  5. 【Linux】多睡/少睡一小时!冬夏令时全解析
  6. net中System.Security.Cryptography 命名空间 下的加密算法
  7. Cookie介绍及JavaScript操作Cookie方法详解
  8. 小贝_mysql建表以及列属性
  9. ThinkPHP 3.1.2 模板中的基本语法<1>
  10. MDCC为移动开发者服务:一看、一聊、一聚
  11. ASP微信开发获取用户经纬度
  12. Stack by pointer
  13. oracle创建表空间、创建用户并赋予权限
  14. 预测python数据分析师的工资
  15. 如何运用git实现版本控制
  16. JavaScript 加解密库(crypto-js)
  17. Optaplanner - 从探究示例中的hello world,初步认识规划引擎的运行步骤。
  18. Zabbix监控进程(进程消失后钉钉报警)
  19. 详解.NET IL代码(一)
  20. 如何在Windows 10上访问NFS的share

热门文章

  1. User Browsing Model简介
  2. CF #335 div1 A. Sorting Railway Cars
  3. 看我如何从一个APK到最终拿下域管理权限
  4. 需求收集实例三之 FM
  5. ssh公钥认证原理及设置root外的其他用户登录ssh
  6. String属于“假引用类型”,代码为证(一个String引发的血案...)
  7. 如何使用angularJs
  8. 学习MVC之租房网站(十)-预约和跟单
  9. 抓包工具 Charles 使用心得
  10. React-Router 4 的新玩意儿