laravel-容器笔记

关于主要几个方法的注释, 如果解决依赖注入问题

   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 }

猜你喜欢

转载自www.cnblogs.com/wangjianheng/p/12219049.html