关于主要几个方法的注释, 如果解决依赖注入问题
1 <?php 2 3 namespace Illuminate\Container; 4 5 use Closure; 6 use Exception; 7 use ArrayAccess; 8 use LogicException; 9 use ReflectionClass; 10 use ReflectionException; 11 use ReflectionParameter; 12 use Illuminate\Support\Arr; 13 use Illuminate\Contracts\Container\BindingResolutionException; 14 use Illuminate\Contracts\Container\Container as ContainerContract; 15 16 class Container implements ArrayAccess, ContainerContract 17 { 18 19 protected static $instance; 20 21 /** 22 * An array of the types that have been resolved. 23 * 24 * @var bool[] 25 */ 26 protected $resolved = []; 27 28 //绑定关系 29 protected $bindings = []; 30 31 /** 32 * The container's method bindings. 33 * 34 * @var \Closure[] 35 */ 36 protected $methodBindings = []; 37 38 //主要用于存储共享实例 39 protected $instances = []; 40 41 //别名 42 protected $aliases = []; 43 44 //所有别名, 多次设置应该都是有效的 45 protected $abstractAliases = []; 46 47 //扩展绑定 48 protected $extenders = []; 49 50 //设置标签 51 protected $tags = []; 52 53 54 //build过的实例名称 55 protected $buildStack = []; 56 57 //实例化对象的参数 58 protected $with = []; 59 60 //上下文绑定关系 61 public $contextual = []; 62 63 /** 64 * All of the registered rebound callbacks. 65 * 66 * @var array[] 67 */ 68 protected $reboundCallbacks = []; 69 70 //针对resolve的一个回调函数数组 71 protected $globalResolvingCallbacks = []; 72 73 /** 74 * All of the global after resolving callbacks. 75 * 76 * @var \Closure[] 77 */ 78 protected $globalAfterResolvingCallbacks = []; 79 80 //针对resolve某个特定实例时的回调函数数组 81 protected $resolvingCallbacks = []; 82 83 /** 84 * All of the after resolving callbacks by class type. 85 * 86 * @var array[] 87 */ 88 protected $afterResolvingCallbacks = []; 89 90 /** 91 * 用于情况绑定, 大概有两种用法, $concrete可以传个数组 92 * (1)绑定初始值 $app->when('user')->need('$name')->give('Bob'); 93 * 实例化user的时候, 构造函数需要参数$name, 那么传值为Bob 94 * 95 * (2)绑定实例 $container->when('eat')->needs('fruit')->give('apple'); 96 * 也可以写成这样 $container->when('eat')->needs('fruit')->give(function() { 97 * return new apple(); 98 * }); 99 * 实例化eat的时候, 构造函数需要实现fruit接口的实例, 那么传值apple的实例 100 * 101 * 区分两者可以根据needs中是否存在$符号 102 */ 103 public function when($concrete) 104 { 105 $aliases = []; 106 107 foreach (Arr::wrap($concrete) as $c) { 108 $aliases[] = $this->getAlias($c); 109 } 110 111 //这里将值保存在contextual中,格式大概为 112 //Array ( 113 // 'eat' => Array( 114 // 'fruit' => 'apple', 115 // ), 116 // 'user' => Array( 117 // '$name' => 'Bob', 118 // ) 119 //) 120 return new ContextualBindingBuilder($this, $aliases); 121 } 122 123 /** 124 * Determine if the given abstract type has been bound. 125 * 126 * @param string $abstract 127 * @return bool 128 */ 129 public function bound($abstract) 130 { 131 return isset($this->bindings[$abstract]) || 132 isset($this->instances[$abstract]) || 133 $this->isAlias($abstract); 134 } 135 136 /** 137 * {@inheritdoc} 138 */ 139 public function has($id) 140 { 141 return $this->bound($id); 142 } 143 144 /** 145 * Determine if the given abstract type has been resolved. 146 * 147 * @param string $abstract 148 * @return bool 149 */ 150 public function resolved($abstract) 151 { 152 if ($this->isAlias($abstract)) { 153 $abstract = $this->getAlias($abstract); 154 } 155 156 return isset($this->resolved[$abstract]) || 157 isset($this->instances[$abstract]); 158 } 159 160 /** 161 * 是否为共享实例 162 */ 163 public function isShared($abstract) 164 { 165 return isset($this->instances[$abstract]) || 166 (isset($this->bindings[$abstract]['shared']) && 167 $this->bindings[$abstract]['shared'] === true); 168 } 169 170 /** 171 * 是否设置过别名 172 */ 173 public function isAlias($name) 174 { 175 return isset($this->aliases[$name]); 176 } 177 178 179 /** 180 * 绑定抽象类与实例的关系,例子: 181 * interface fruit {} 182 * class apple implements fruit{} 183 * class banana implements fruit{} 184 * class eat { 185 * public function __construct(fruit $fruit) { 186 * $this->fruit = $fruit; 187 * } 188 * $container->bind('fruit', 'apple');[这里也可以直接传个匿名函数] 189 * $container->bind('eat'); 190 * $app = $container->make('eat'); 191 * 192 * eat依赖实现fruit接口的实例, bind('fruit', 'apple')表示注册apple为fruit的实例 193 * 之后再make('eat'),eat中的$this->fruit就是apple的实例 194 */ 195 public function bind($abstract, $concrete = null, $shared = false) 196 { 197 //去除共享实例和别名, 类似于初始化或者清除缓存那种感觉 198 $this->dropStaleInstances($abstract); 199 200 //如果$concrete为null表示没有要绑定的实例, 其本身就是一个具体的实例 201 //直接实例化就可以了, 为$concrete赋值$abstract。 202 //效果在getClosure中,判定如果两者相等直接build($abstract), 生成一个实例 203 //如果不相等要先执行resolve, 从binding中根据$abstract找到要生成的具体实例, 然后再build 204 //比如bind('水果', '苹果') - bind('水果', '苹果') 205 if (is_null($concrete)) { 206 $concrete = $abstract; 207 } 208 209 //如果$concrete不是匿名函数,将构造一个匿名函数。 210 if (! $concrete instanceof Closure) { 211 $concrete = $this->getClosure($abstract, $concrete); 212 } 213 214 //以$abstract为键值,将匿名函数和shared的值存在bindings中,如果shared为true表示共享实例 215 $this->bindings[$abstract] = compact('concrete', 'shared'); 216 217 218 if ($this->resolved($abstract)) { 219 $this->rebound($abstract); 220 } 221 } 222 223 /** 224 * 生成匿名函数 225 */ 226 protected function getClosure($abstract, $concrete) 227 { 228 return function ($container, $parameters = []) use ($abstract, $concrete) { 229 if ($abstract == $concrete) { 230 return $container->build($concrete); 231 } 232 233 return $container->resolve( 234 $concrete, $parameters, $raiseEvents = false 235 ); 236 }; 237 } 238 239 /** 240 * Determine if the container has a method binding. 241 * 242 * @param string $method 243 * @return bool 244 */ 245 public function hasMethodBinding($method) 246 { 247 return isset($this->methodBindings[$method]); 248 } 249 250 /** 251 * Bind a callback to resolve with Container::call. 252 * 253 * @param array|string $method 254 * @param \Closure $callback 255 * @return void 256 */ 257 public function bindMethod($method, $callback) 258 { 259 $this->methodBindings[$this->parseBindMethod($method)] = $callback; 260 } 261 262 /** 263 * Get the method to be bound in class@method format. 264 * 265 * @param array|string $method 266 * @return string 267 */ 268 protected function parseBindMethod($method) 269 { 270 if (is_array($method)) { 271 return $method[0].'@'.$method[1]; 272 } 273 274 return $method; 275 } 276 277 /** 278 * Get the method binding for the given method. 279 * 280 * @param string $method 281 * @param mixed $instance 282 * @return mixed 283 */ 284 public function callMethodBinding($method, $instance) 285 { 286 return call_user_func($this->methodBindings[$method], $instance, $this); 287 } 288 289 /** 290 * Add a contextual binding to the container. 291 * 292 * @param string $concrete 293 * @param string $abstract 294 * @param \Closure|string $implementation 295 * @return void 296 */ 297 public function addContextualBinding($concrete, $abstract, $implementation) 298 { 299 $this->contextual[$concrete][$this->getAlias($abstract)] = $implementation; 300 } 301 302 /** 303 * Register a binding if it hasn't already been registered. 304 * 305 * @param string $abstract 306 * @param \Closure|string|null $concrete 307 * @param bool $shared 308 * @return void 309 */ 310 public function bindIf($abstract, $concrete = null, $shared = false) 311 { 312 if (! $this->bound($abstract)) { 313 $this->bind($abstract, $concrete, $shared); 314 } 315 } 316 317 /** 318 * Register a shared binding in the container. 319 * 320 * @param string $abstract 321 * @param \Closure|string|null $concrete 322 * @return void 323 */ 324 public function singleton($abstract, $concrete = null) 325 { 326 $this->bind($abstract, $concrete, true); 327 } 328 329 /** 330 * Register a shared binding if it hasn't already been registered. 331 * 332 * @param string $abstract 333 * @param \Closure|string|null $concrete 334 * @return void 335 */ 336 public function singletonIf($abstract, $concrete = null) 337 { 338 if (! $this->bound($abstract)) { 339 $this->singleton($abstract, $concrete); 340 } 341 } 342 343 /** 344 * 扩展绑定, 多次设置扩展会全部依次执行, 而不是覆盖 345 * 用法示例: 346 class apple {} 347 $container->extend('apple', function($obj, $c){ 348 $obj->extend = 'i was extend'; 349 return $obj; 350 }); 351 352 $container->extend('apple', function($obj, $c){ 353 $obj->extend .= ' and extend'; 354 return $obj; 355 }); 356 357 $app = $container->make('apple'); 358 echo $app->extend; 359 */ 360 public function extend($abstract, Closure $closure) 361 { 362 $abstract = $this->getAlias($abstract); 363 364 //如果存在共享实例, 需要对该实例进行自定义扩展 365 if (isset($this->instances[$abstract])) { 366 $this->instances[$abstract] = $closure($this->instances[$abstract], $this); 367 368 $this->rebound($abstract); 369 } else { 370 //这里先记录下, extenders会在resolve中用到 371 $this->extenders[$abstract][] = $closure; 372 373 if ($this->resolved($abstract)) { 374 $this->rebound($abstract); 375 } 376 } 377 } 378 379 /** 380 * Register an existing instance as shared in the container. 381 * 382 * @param string $abstract 383 * @param mixed $instance 384 * @return mixed 385 */ 386 public function instance($abstract, $instance) 387 { 388 $this->removeAbstractAlias($abstract); 389 390 $isBound = $this->bound($abstract); 391 392 unset($this->aliases[$abstract]); 393 394 // We'll check to determine if this type has been bound before, and if it has 395 // we will fire the rebound callbacks registered with the container and it 396 // can be updated with consuming classes that have gotten resolved here. 397 $this->instances[$abstract] = $instance; 398 399 if ($isBound) { 400 $this->rebound($abstract); 401 } 402 403 return $instance; 404 } 405 406 /** 407 * Remove an alias from the contextual binding alias cache. 408 * 409 * @param string $searched 410 * @return void 411 */ 412 protected function removeAbstractAlias($searched) 413 { 414 if (! isset($this->aliases[$searched])) { 415 return; 416 } 417 418 foreach ($this->abstractAliases as $abstract => $aliases) { 419 foreach ($aliases as $index => $alias) { 420 if ($alias == $searched) { 421 unset($this->abstractAliases[$abstract][$index]); 422 } 423 } 424 } 425 } 426 427 /** 428 * 为类打上标签, 类似于打包 一个实例也可以有多个标签 429 */ 430 public function tag($abstracts, $tags) 431 { 432 $tags = is_array($tags) ? $tags : array_slice(func_get_args(), 1); 433 434 foreach ($tags as $tag) { 435 if (! isset($this->tags[$tag])) { 436 $this->tags[$tag] = []; 437 } 438 439 foreach ((array) $abstracts as $abstract) { 440 $this->tags[$tag][] = $abstract; 441 } 442 } 443 } 444 445 /** 446 * 依次返回这个tag中的实例 447 * 举个例子, 假如有一天你想要所有的水果依次说出自己的颜色 448 interface fruit { 449 public function sayColor(); 450 } 451 class apple implements fruit{ 452 public function sayColor() { 453 echo 'I am red'; 454 } 455 } 456 class banana implements fruit{ 457 public function sayColor() { 458 echo 'I am yellow'; 459 } 460 } 461 462 $container->tag(['apple', 'banana'], 'fruit'); 463 $fruits = $container->tagged('fruit')->getIterator(); 464 foreach ($fruits as $fruit) { 465 $fruit->sayColor(); 466 } 467 */ 468 public function tagged($tag) 469 { 470 if (! isset($this->tags[$tag])) { 471 return []; 472 } 473 474 //这里传入了一个生成器的匿名函数, 和count 475 return new RewindableGenerator(function () use ($tag) { 476 foreach ($this->tags[$tag] as $abstract) { 477 yield $this->make($abstract); 478 } 479 }, count($this->tags[$tag])); 480 } 481 482 /** 483 * 设置别名 484 */ 485 public function alias($abstract, $alias) 486 { 487 if ($alias === $abstract) { 488 throw new LogicException("[{$abstract}] is aliased to itself."); 489 } 490 491 $this->aliases[$alias] = $abstract; 492 493 $this->abstractAliases[$abstract][] = $alias; 494 } 495 496 /** 497 * Bind a new callback to an abstract's rebind event. 498 * 499 * @param string $abstract 500 * @param \Closure $callback 501 * @return mixed 502 */ 503 public function rebinding($abstract, Closure $callback) 504 { 505 $this->reboundCallbacks[$abstract = $this->getAlias($abstract)][] = $callback; 506 507 if ($this->bound($abstract)) { 508 return $this->make($abstract); 509 } 510 } 511 512 /** 513 * Refresh an instance on the given target and method. 514 * 515 * @param string $abstract 516 * @param mixed $target 517 * @param string $method 518 * @return mixed 519 */ 520 public function refresh($abstract, $target, $method) 521 { 522 return $this->rebinding($abstract, function ($app, $instance) use ($target, $method) { 523 $target->{$method}($instance); 524 }); 525 } 526 527 /** 528 * Fire the "rebound" callbacks for the given abstract type. 529 * 530 * @param string $abstract 531 * @return void 532 */ 533 protected function rebound($abstract) 534 { 535 $instance = $this->make($abstract); 536 537 foreach ($this->getReboundCallbacks($abstract) as $callback) { 538 call_user_func($callback, $this, $instance); 539 } 540 } 541 542 /** 543 * Get the rebound callbacks for a given type. 544 * 545 * @param string $abstract 546 * @return array 547 */ 548 protected function getReboundCallbacks($abstract) 549 { 550 return $this->reboundCallbacks[$abstract] ?? []; 551 } 552 553 /** 554 * Wrap the given closure such that its dependencies will be injected when executed. 555 * 556 * @param \Closure $callback 557 * @param array $parameters 558 * @return \Closure 559 */ 560 public function wrap(Closure $callback, array $parameters = []) 561 { 562 return function () use ($callback, $parameters) { 563 return $this->call($callback, $parameters); 564 }; 565 } 566 567 /** 568 * Call the given Closure / class@method and inject its dependencies. 569 * 570 * @param callable|string $callback 571 * @param array $parameters 572 * @param string|null $defaultMethod 573 * @return mixed 574 */ 575 public function call($callback, array $parameters = [], $defaultMethod = null) 576 { 577 return BoundMethod::call($this, $callback, $parameters, $defaultMethod); 578 } 579 580 /** 581 * Get a closure to resolve the given type from the container. 582 * 583 * @param string $abstract 584 * @return \Closure 585 */ 586 public function factory($abstract) 587 { 588 return function () use ($abstract) { 589 return $this->make($abstract); 590 }; 591 } 592 593 /** 594 * An alias function name for make(). 595 * 596 * @param string $abstract 597 * @param array $parameters 598 * @return mixed 599 */ 600 public function makeWith($abstract, array $parameters = []) 601 { 602 return $this->make($abstract, $parameters); 603 } 604 605 /** 606 * Resolve the given type from the container. 607 * 608 * @param string $abstract 609 * @param array $parameters 610 * @return mixed 611 * 612 * @throws \Illuminate\Contracts\Container\BindingResolutionException 613 */ 614 public function make($abstract, array $parameters = []) 615 { 616 return $this->resolve($abstract, $parameters); 617 } 618 619 /** 620 * {@inheritdoc} 621 */ 622 public function get($id) 623 { 624 try { 625 return $this->resolve($id); 626 } catch (Exception $e) { 627 if ($this->has($id)) { 628 throw $e; 629 } 630 631 throw new EntryNotFoundException($id); 632 } 633 } 634 635 /** 636 * 构造环境, 生成实例 637 */ 638 protected function resolve($abstract, $parameters = [], $raiseEvents = true) 639 { 640 //获取别名 641 $abstract = $this->getAlias($abstract); 642 643 //这个标志只是判断是否能够使用$this->instances, 类似缓存。 644 //如果既没有传入参数, 之前也没有对参数进行绑定(when->needs->give) 645 //那么通过相同的$abstract生成的实例应该是相同的, 直接返回就行了(在绑定时候设置shared为true) 646 $needsContextualBuild = ! empty($parameters) || ! is_null( 647 $this->getContextualConcrete($abstract) 648 ); 649 650 651 //如果在bind是设置shared为true,下次再make相同的$abstract会直接返回之前make的实例, 在下面存进去的 652 if (isset($this->instances[$abstract]) && ! $needsContextualBuild) { 653 return $this->instances[$abstract]; 654 } 655 656 $this->with[] = $parameters; 657 658 //获取绑定的实例 659 $concrete = $this->getConcrete($abstract); 660 661 //可以追一下getConcrete方法, 如果是之前设置过上下文绑定会走make, 其他情况应该都走build 662 //先看一下findInContextualBindings的例子, 然后捋一下顺序 663 //起始执行make('eat'), 因为此时buildStack还是空的, findInContextualBindings会返回null, 所以执行build('eat') 664 //build会在buildStack中追加了eat 665 //并且会检测eat的构造函数, 发现了依赖关系, 接着执行make('fruit') 666 //在上面getConcrete('eat'), 会返回'apple'。 isBuildable判定为false, 所以会执行make('apple') 667 if ($this->isBuildable($concrete, $abstract)) { 668 $object = $this->build($concrete); 669 } else { 670 $object = $this->make($concrete); 671 } 672 673 674 //如果有额外扩展, 则执行这个扩展 675 foreach ($this->getExtenders($abstract) as $extender) { 676 $object = $extender($object, $this); 677 } 678 679 //就是在这存进去的 680 if ($this->isShared($abstract) && ! $needsContextualBuild) { 681 $this->instances[$abstract] = $object; 682 } 683 684 //执行监听事件 685 if ($raiseEvents) { 686 $this->fireResolvingCallbacks($abstract, $object); 687 } 688 689 690 //标记已经生成过 691 $this->resolved[$abstract] = true; 692 693 array_pop($this->with); 694 695 return $object; 696 } 697 698 /** 699 * 根据抽象名称取获取绑定的实例 700 */ 701 protected function getConcrete($abstract) 702 { 703 //这里返回之前的上下文绑定过 704 if (! is_null($concrete = $this->getContextualConcrete($abstract))) { 705 return $concrete; 706 } 707 708 //这里返回之前bind过的匿名函数 709 if (isset($this->bindings[$abstract])) { 710 return $this->bindings[$abstract]['concrete']; 711 } 712 713 return $abstract; 714 } 715 716 /** 717 * 获取之前绑定的上下文关系(多检测了别名) 718 */ 719 protected function getContextualConcrete($abstract) 720 { 721 //之前是否绑定过上下文关系 722 if (! is_null($binding = $this->findInContextualBindings($abstract))) { 723 return $binding; 724 } 725 726 727 //这里找一下别名, 如果没有别名就返回空 728 if (empty($this->abstractAliases[$abstract])) { 729 return; 730 } 731 732 //如果有别名再找一下是否按照别名设置过 733 foreach ($this->abstractAliases[$abstract] as $alias) { 734 if (! is_null($binding = $this->findInContextualBindings($alias))) { 735 return $binding; 736 } 737 } 738 } 739 740 /** 741 * 之前设置的上下文绑定 742 */ 743 protected function findInContextualBindings($abstract) 744 { 745 //每次build出一个实例之后, 会将其名字放入到堆栈($this->buildStack)中 746 //然后检测其构造函数的入参方式, 继续make这些参数。 747 //interface fruit {} 748 //class apple implements fruit{} 749 750 //class eat { 751 // public function __construct(fruit $fruit) { 752 // $this->fruit = $fruit; 753 // } 754 //} 755 //$container->when('eat')->needs('fruit')->give('apple'); 756 //$app = $container->make('eat'); 757 //build完eat之后, 将eat放在buildStack最后,接着make fruit,因为之前上下文绑定关系give('apple') 758 //$this->contextual['eat']['fruit']的值为'apple', 然后返回apple 759 return $this->contextual[end($this->buildStack)][$abstract] ?? null; 760 } 761 762 763 /** 764 * 是否可以build 765 */ 766 protected function isBuildable($concrete, $abstract) 767 { 768 return $concrete === $abstract || $concrete instanceof Closure; 769 } 770 771 /** 772 * 构造一个实例 773 */ 774 public function build($concrete) 775 { 776 //如果之前执行了bind, $concrete会是个匿名函数 777 //这里会执行这个函数, 出去绕一圈还是会回到这里的 778 if ($concrete instanceof Closure) { 779 return $concrete($this, $this->getLastParameterOverride()); 780 } 781 782 try { 783 //反射 784 $reflector = new ReflectionClass($concrete); 785 } catch (ReflectionException $e) { 786 throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e); 787 } 788 789 790 //如果不能实例化直接抛出异常 791 if (! $reflector->isInstantiable()) { 792 return $this->notInstantiable($concrete); 793 } 794 795 //就是在这里放进去的 796 $this->buildStack[] = $concrete; 797 798 //检查是否有构造函数 799 $constructor = $reflector->getConstructor(); 800 801 //如果没有构造函数, 就没有入参也没有依赖关系, 直接实例化返回就行了 802 if (is_null($constructor)) { 803 array_pop($this->buildStack); 804 805 return new $concrete; 806 } 807 808 //这里获取入参 809 $dependencies = $constructor->getParameters(); 810 811 812 //这里解决依赖关系, 或入参 813 try { 814 $instances = $this->resolveDependencies($dependencies); 815 } catch (BindingResolutionException $e) { 816 array_pop($this->buildStack); 817 818 throw $e; 819 } 820 821 //弹出, 假如A依赖B, B依赖C, C依赖D 这里可能会有很多层 822 array_pop($this->buildStack); 823 824 //生成实例, 这里已经把依赖注入了 825 return $reflector->newInstanceArgs($instances); 826 } 827 828 /** 829 * 解决依赖关系 830 */ 831 protected function resolveDependencies(array $dependencies) 832 { 833 $results = []; 834 835 foreach ($dependencies as $dependency) { 836 //假如这个参数已经由外层自己传过来了, 就直接拿过来用 837 if ($this->hasParameterOverride($dependency)) { 838 $results[] = $this->getParameterOverride($dependency); 839 840 continue; 841 } 842 843 844 //如果不为null, 说明这个参数需要传入一个类 845 $results[] = is_null($dependency->getClass()) 846 ? $this->resolvePrimitive($dependency) 847 : $this->resolveClass($dependency); 848 } 849 850 return $results; 851 } 852 853 /** 854 * 判断依赖参数是否已经传入了 855 */ 856 protected function hasParameterOverride($dependency) 857 { 858 return array_key_exists( 859 $dependency->name, $this->getLastParameterOverride() 860 ); 861 } 862 863 /** 864 * 获取传入对应参数的值 865 */ 866 protected function getParameterOverride($dependency) 867 { 868 return $this->getLastParameterOverride()[$dependency->name]; 869 } 870 871 /** 872 * 获取这个实例的传入参数 873 */ 874 protected function getLastParameterOverride() 875 { 876 return count($this->with) ? end($this->with) : []; 877 } 878 879 /** 880 * 解决依赖参数(该参数是一个普通变量) 881 */ 882 protected function resolvePrimitive(ReflectionParameter $parameter) 883 { 884 //根据这个实例获取绑定过参数(when那个) 885 if (! is_null($concrete = $this->getContextualConcrete('$'.$parameter->name))) { 886 return $concrete instanceof Closure ? $concrete($this) : $concrete; 887 } 888 889 //要实现的类中的构造函数中设置了默认值 890 if ($parameter->isDefaultValueAvailable()) { 891 return $parameter->getDefaultValue(); 892 } 893 894 //抛出异常 895 $this->unresolvablePrimitive($parameter); 896 } 897 898 /** 899 * 解决依赖参数(该参数是一个类) 900 */ 901 protected function resolveClass(ReflectionParameter $parameter) 902 { 903 try { 904 //直接再make就行了 905 return $this->make($parameter->getClass()->name); 906 } 907 908 catch (BindingResolutionException $e) { 909 //如果make失败, 查看构造函数中是否设置了默认值 910 //如果还没有设置默认值就抛出异常 911 if ($parameter->isOptional()) { 912 return $parameter->getDefaultValue(); 913 } 914 915 throw $e; 916 } 917 } 918 919 /** 920 * Throw an exception that the concrete is not instantiable. 921 * 922 * @param string $concrete 923 * @return void 924 * 925 * @throws \Illuminate\Contracts\Container\BindingResolutionException 926 */ 927 protected function notInstantiable($concrete) 928 { 929 if (! empty($this->buildStack)) { 930 $previous = implode(', ', $this->buildStack); 931 932 $message = "Target [$concrete] is not instantiable while building [$previous]."; 933 } else { 934 $message = "Target [$concrete] is not instantiable."; 935 } 936 937 throw new BindingResolutionException($message); 938 } 939 940 /** 941 * 创建一个对象的时候, 无法找到传入参数 942 */ 943 protected function unresolvablePrimitive(ReflectionParameter $parameter) 944 { 945 $message = "Unresolvable dependency resolving [$parameter] in class {$parameter->getDeclaringClass()->getName()}"; 946 947 throw new BindingResolutionException($message); 948 } 949 950 /** 951 * 设置生成示例的监听事件, 可以监听全部, 也可以只是监听生成某个示例 952 * 前提是调用resolve时$raiseEvents设置为true才会触发 953 * 例子 954 class apple {} 955 //生成apple时执行该函数 956 $container->resolving('apple', function ($obj, $c){ 957 echo 'I have made apple'; 958 }); 959 960 //生成任何示例都会执行该函数 961 $container->resolving(function ($obj, $c){ 962 echo 'I have made something'; 963 }); 964 965 $app = $container->make('apple'); 966 */ 967 public function resolving($abstract, Closure $callback = null) 968 { 969 if (is_string($abstract)) { 970 $abstract = $this->getAlias($abstract); 971 } 972 973 //这总是全局的 974 if (is_null($callback) && $abstract instanceof Closure) { 975 $this->globalResolvingCallbacks[] = $abstract; 976 } else { 977 //这种只是针对某个实例的 978 $this->resolvingCallbacks[$abstract][] = $callback; 979 } 980 } 981 982 /** 983 * Register a new after resolving callback for all types. 984 * 985 * @param \Closure|string $abstract 986 * @param \Closure|null $callback 987 * @return void 988 */ 989 public function afterResolving($abstract, Closure $callback = null) 990 { 991 if (is_string($abstract)) { 992 $abstract = $this->getAlias($abstract); 993 } 994 995 if ($abstract instanceof Closure && is_null($callback)) { 996 $this->globalAfterResolvingCallbacks[] = $abstract; 997 } else { 998 $this->afterResolvingCallbacks[$abstract][] = $callback; 999 } 1000 } 1001 1002 /** 1003 * Fire all of the resolving callbacks. 1004 * 1005 * @param string $abstract 1006 * @param mixed $object 1007 * @return void 1008 */ 1009 protected function fireResolvingCallbacks($abstract, $object) 1010 { 1011 $this->fireCallbackArray($object, $this->globalResolvingCallbacks); 1012 1013 $this->fireCallbackArray( 1014 $object, $this->getCallbacksForType($abstract, $object, $this->resolvingCallbacks) 1015 ); 1016 1017 $this->fireAfterResolvingCallbacks($abstract, $object); 1018 } 1019 1020 /** 1021 * Fire all of the after resolving callbacks. 1022 * 1023 * @param string $abstract 1024 * @param mixed $object 1025 * @return void 1026 */ 1027 protected function fireAfterResolvingCallbacks($abstract, $object) 1028 { 1029 $this->fireCallbackArray($object, $this->globalAfterResolvingCallbacks); 1030 1031 $this->fireCallbackArray( 1032 $object, $this->getCallbacksForType($abstract, $object, $this->afterResolvingCallbacks) 1033 ); 1034 } 1035 1036 /** 1037 * Get all callbacks for a given type. 1038 * 1039 * @param string $abstract 1040 * @param object $object 1041 * @param array $callbacksPerType 1042 * 1043 * @return array 1044 */ 1045 protected function getCallbacksForType($abstract, $object, array $callbacksPerType) 1046 { 1047 $results = []; 1048 1049 foreach ($callbacksPerType as $type => $callbacks) { 1050 if ($type === $abstract || $object instanceof $type) { 1051 $results = array_merge($results, $callbacks); 1052 } 1053 } 1054 1055 return $results; 1056 } 1057 1058 /** 1059 * Fire an array of callbacks with an object. 1060 * 1061 * @param mixed $object 1062 * @param array $callbacks 1063 * @return void 1064 */ 1065 protected function fireCallbackArray($object, array $callbacks) 1066 { 1067 foreach ($callbacks as $callback) { 1068 $callback($object, $this); 1069 } 1070 } 1071 1072 /** 1073 * 返回绑定关系 1074 */ 1075 public function getBindings() 1076 { 1077 return $this->bindings; 1078 } 1079 1080 /** 1081 * 获取别名 1082 */ 1083 public function getAlias($abstract) 1084 { 1085 if (! isset($this->aliases[$abstract])) { 1086 return $abstract; 1087 } 1088 1089 //链式关系, 如果设置A的别名是B, 设置B的别名是C; 如果我输入是C, 则返回的应该是A 1090 return $this->getAlias($this->aliases[$abstract]); 1091 } 1092 1093 1094 //获取扩展绑定 1095 protected function getExtenders($abstract) 1096 { 1097 $abstract = $this->getAlias($abstract); 1098 1099 return $this->extenders[$abstract] ?? []; 1100 } 1101 1102 1103 //删除扩展绑定 1104 public function forgetExtenders($abstract) 1105 { 1106 unset($this->extenders[$this->getAlias($abstract)]); 1107 } 1108 1109 /** 1110 * 去除共享实例和别名 1111 */ 1112 protected function dropStaleInstances($abstract) 1113 { 1114 unset($this->instances[$abstract], $this->aliases[$abstract]); 1115 } 1116 1117 /** 1118 * Remove a resolved instance from the instance cache. 1119 * 1120 * @param string $abstract 1121 * @return void 1122 */ 1123 public function forgetInstance($abstract) 1124 { 1125 unset($this->instances[$abstract]); 1126 } 1127 1128 /** 1129 * Clear all of the instances from the container. 1130 * 1131 * @return void 1132 */ 1133 public function forgetInstances() 1134 { 1135 $this->instances = []; 1136 } 1137 1138 /** 1139 * Flush the container of all bindings and resolved instances. 1140 * 1141 * @return void 1142 */ 1143 public function flush() 1144 { 1145 $this->aliases = []; 1146 $this->resolved = []; 1147 $this->bindings = []; 1148 $this->instances = []; 1149 $this->abstractAliases = []; 1150 } 1151 1152 /** 1153 * Get the globally available instance of the container. 1154 * 1155 * @return static 1156 */ 1157 public static function getInstance() 1158 { 1159 if (is_null(static::$instance)) { 1160 static::$instance = new static; 1161 } 1162 1163 return static::$instance; 1164 } 1165 1166 /** 1167 * Set the shared instance of the container. 1168 * 1169 * @param \Illuminate\Contracts\Container\Container|null $container 1170 * @return \Illuminate\Contracts\Container\Container|static 1171 */ 1172 public static function setInstance(ContainerContract $container = null) 1173 { 1174 return static::$instance = $container; 1175 } 1176 1177 /** 1178 * Determine if a given offset exists. 1179 * 1180 * @param string $key 1181 * @return bool 1182 */ 1183 public function offsetExists($key) 1184 { 1185 return $this->bound($key); 1186 } 1187 1188 /** 1189 * Get the value at a given offset. 1190 * 1191 * @param string $key 1192 * @return mixed 1193 */ 1194 public function offsetGet($key) 1195 { 1196 return $this->make($key); 1197 } 1198 1199 /** 1200 * Set the value at a given offset. 1201 * 1202 * @param string $key 1203 * @param mixed $value 1204 * @return void 1205 */ 1206 public function offsetSet($key, $value) 1207 { 1208 $this->bind($key, $value instanceof Closure ? $value : function () use ($value) { 1209 return $value; 1210 }); 1211 } 1212 1213 /** 1214 * Unset the value at a given offset. 1215 * 1216 * @param string $key 1217 * @return void 1218 */ 1219 public function offsetUnset($key) 1220 { 1221 unset($this->bindings[$key], $this->instances[$key], $this->resolved[$key]); 1222 } 1223 1224 /** 1225 * Dynamically access container services. 1226 * 1227 * @param string $key 1228 * @return mixed 1229 */ 1230 public function __get($key) 1231 { 1232 return $this[$key]; 1233 } 1234 1235 /** 1236 * Dynamically set container services. 1237 * 1238 * @param string $key 1239 * @param mixed $value 1240 * @return void 1241 */ 1242 public function __set($key, $value) 1243 { 1244 $this[$key] = $value; 1245 } 1246 }