直接上代码吧:

  1. <?php
  2. namespace App;
  3. class Container
  4. {
  5. /**
  6. * 容器绑定,用来装提供的实例或者 提供实例的回调函数
  7. * @var array
  8. */
  9. public $building = [];
  10. /**
  11. * 注册一个绑定到容器
  12. */
  13. public function bind($abstract, $concrete = null, $shared = false)
  14. {
  15. if (is_null($concrete)) {
  16. $concrete = $abstract;
  17. }
  18. if ($concrete instanceof Closure) {
  19. $concrete = $this->getClosure($abstract, $concrete);
  20. }
  21. $this->building[$abstract] = compact("concrete", "shared");
  22. }
  23. //注册一个共享的绑定 单例
  24. public function singleton($abstract, $concrete, $shared = true)
  25. {
  26. $this->bind($abstract, $concrete, $shared);
  27. }
  28. /**
  29. * 默认生成实例的回调闭包
  30. *
  31. * @param $abstract
  32. * @param $concrete
  33. * @return Closure
  34. */
  35. public function getClosure($abstract, $concrete)
  36. {
  37. return function ($c) use ($abstract, $concrete) {
  38. $method = ($abstract == $concrete) ? 'build' : 'make';
  39. return $c->$method($concrete);
  40. };
  41. }
  42. /**
  43. * 生成实例
  44. */
  45. public function make($abstract)
  46. {
  47. $concrete = $this->getConcrete($abstract);
  48. if ($this->isBuildable($concrete, $abstract)) {
  49. $object = $this->build($concrete);
  50. } else {
  51. $object = $this->make($concrete);
  52. }
  53. return $object;
  54. }
  55. /**
  56. * 获取绑定的回调函数
  57. */
  58. public function getConcrete($abstract)
  59. {
  60. if (!isset($this->building[$abstract])) {
  61. return $abstract;
  62. }
  63. return $this->building[$abstract]['concrete'];
  64. }
  65. /**
  66. * 判断 是否 可以创建服务实体
  67. */
  68. public function isBuildable($concrete, $abstract)
  69. {
  70. return $concrete === $abstract || $concrete instanceof Closure;
  71. }
  72. /**
  73. * 根据实例具体名称实例具体对象
  74. */
  75. public function build($concrete)
  76. {
  77. if ($concrete instanceof Closure) {
  78. return $concrete($this);
  79. }
  80. //创建反射对象
  81. $reflector = new \ReflectionClass($concrete);
  82. if (!$reflector->isInstantiable()) {
  83. //抛出异常
  84. throw new \Exception('无法实例化');
  85. }
  86. $constructor = $reflector->getConstructor();
  87. if (is_null($constructor)) {
  88. return new $concrete;
  89. }
  90. $dependencies = $constructor->getParameters();
  91. $instance = $this->getDependencies($dependencies);
  92. return $reflector->newInstanceArgs($instance);
  93. }
  94. //通过反射解决参数依赖
  95. public function getDependencies(array $dependencies)
  96. {
  97. $results = [];
  98. foreach ($dependencies as $dependency) {
  99. $results[] = is_null($dependency->getClass())
  100. ? $this->resolvedNonClass($dependency)
  101. : $this->resolvedClass($dependency);
  102. }
  103. return $results;
  104. }
  105. //解决一个没有类型提示依赖
  106. public function resolvedNonClass(ReflectionParameter $parameter)
  107. {
  108. if ($parameter->isDefaultValueAvailable()) {
  109. return $parameter->getDefaultValue();
  110. }
  111. throw new \Exception('出错');
  112. }
  113. //通过容器解决依赖
  114. public function resolvedClass(ReflectionParameter $parameter)
  115. {
  116. return $this->make($parameter->getClass()->name);
  117. }
  118. }
  119. class Dog
  120. {
  121. public function dogCall()
  122. {
  123. return '汪汪汪';
  124. }
  125. }
  126. class People
  127. {
  128. public $dog = null;
  129. public function __construct()
  130. {
  131. $this->dog = new Dog();
  132. }
  133. public function putDog()
  134. {
  135. return $this->dog->dogCall();
  136. }
  137. }
  138. //实例化容器类
  139. $app = new Container();
  140. //向容器中填充Dog
  141. $app->bind('Dog', 'App\Dog');
  142. //填充People
  143. $app->bind('People', 'App\People');
  144. //通过容器实现依赖注入,完成类的实例化;
  145. $people = $app->make('People');
  146. //调用方法
  147. echo $people->putDog();

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

来源:https://laravel-china.org/articles/4977/laravel-service-container-implementation-principle#reply15

分类: web

标签:   laravel