PageRenderTime 62ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/laravel/framework/src/Illuminate/Container/Container.php

https://gitlab.com/ealexis.t/trends
PHP | 1237 lines | 568 code | 155 blank | 514 comment | 62 complexity | 5635d80ef4e024aa8f16587af7a50d8e MD5 | raw file
  1. <?php
  2. namespace Illuminate\Container;
  3. use Closure;
  4. use ArrayAccess;
  5. use ReflectionClass;
  6. use ReflectionMethod;
  7. use ReflectionFunction;
  8. use ReflectionParameter;
  9. use InvalidArgumentException;
  10. use Illuminate\Contracts\Container\BindingResolutionException;
  11. use Illuminate\Contracts\Container\Container as ContainerContract;
  12. class Container implements ArrayAccess, ContainerContract
  13. {
  14. /**
  15. * The current globally available container (if any).
  16. *
  17. * @var static
  18. */
  19. protected static $instance;
  20. /**
  21. * An array of the types that have been resolved.
  22. *
  23. * @var array
  24. */
  25. protected $resolved = [];
  26. /**
  27. * The container's bindings.
  28. *
  29. * @var array
  30. */
  31. protected $bindings = [];
  32. /**
  33. * The container's shared instances.
  34. *
  35. * @var array
  36. */
  37. protected $instances = [];
  38. /**
  39. * The registered type aliases.
  40. *
  41. * @var array
  42. */
  43. protected $aliases = [];
  44. /**
  45. * The extension closures for services.
  46. *
  47. * @var array
  48. */
  49. protected $extenders = [];
  50. /**
  51. * All of the registered tags.
  52. *
  53. * @var array
  54. */
  55. protected $tags = [];
  56. /**
  57. * The stack of concretions currently being built.
  58. *
  59. * @var array
  60. */
  61. protected $buildStack = [];
  62. /**
  63. * The contextual binding map.
  64. *
  65. * @var array
  66. */
  67. public $contextual = [];
  68. /**
  69. * All of the registered rebound callbacks.
  70. *
  71. * @var array
  72. */
  73. protected $reboundCallbacks = [];
  74. /**
  75. * All of the global resolving callbacks.
  76. *
  77. * @var array
  78. */
  79. protected $globalResolvingCallbacks = [];
  80. /**
  81. * All of the global after resolving callbacks.
  82. *
  83. * @var array
  84. */
  85. protected $globalAfterResolvingCallbacks = [];
  86. /**
  87. * All of the resolving callbacks by class type.
  88. *
  89. * @var array
  90. */
  91. protected $resolvingCallbacks = [];
  92. /**
  93. * All of the after resolving callbacks by class type.
  94. *
  95. * @var array
  96. */
  97. protected $afterResolvingCallbacks = [];
  98. /**
  99. * Define a contextual binding.
  100. *
  101. * @param string $concrete
  102. * @return \Illuminate\Contracts\Container\ContextualBindingBuilder
  103. */
  104. public function when($concrete)
  105. {
  106. $concrete = $this->normalize($concrete);
  107. return new ContextualBindingBuilder($this, $concrete);
  108. }
  109. /**
  110. * Determine if the given abstract type has been bound.
  111. *
  112. * @param string $abstract
  113. * @return bool
  114. */
  115. public function bound($abstract)
  116. {
  117. $abstract = $this->normalize($abstract);
  118. return isset($this->bindings[$abstract]) || isset($this->instances[$abstract]) || $this->isAlias($abstract);
  119. }
  120. /**
  121. * Determine if the given abstract type has been resolved.
  122. *
  123. * @param string $abstract
  124. * @return bool
  125. */
  126. public function resolved($abstract)
  127. {
  128. $abstract = $this->normalize($abstract);
  129. if ($this->isAlias($abstract)) {
  130. $abstract = $this->getAlias($abstract);
  131. }
  132. return isset($this->resolved[$abstract]) || isset($this->instances[$abstract]);
  133. }
  134. /**
  135. * Determine if a given string is an alias.
  136. *
  137. * @param string $name
  138. * @return bool
  139. */
  140. public function isAlias($name)
  141. {
  142. return isset($this->aliases[$this->normalize($name)]);
  143. }
  144. /**
  145. * Register a binding with the container.
  146. *
  147. * @param string|array $abstract
  148. * @param \Closure|string|null $concrete
  149. * @param bool $shared
  150. * @return void
  151. */
  152. public function bind($abstract, $concrete = null, $shared = false)
  153. {
  154. $abstract = $this->normalize($abstract);
  155. $concrete = $this->normalize($concrete);
  156. // If the given types are actually an array, we will assume an alias is being
  157. // defined and will grab this "real" abstract class name and register this
  158. // alias with the container so that it can be used as a shortcut for it.
  159. if (is_array($abstract)) {
  160. list($abstract, $alias) = $this->extractAlias($abstract);
  161. $this->alias($abstract, $alias);
  162. }
  163. // If no concrete type was given, we will simply set the concrete type to the
  164. // abstract type. This will allow concrete type to be registered as shared
  165. // without being forced to state their classes in both of the parameter.
  166. $this->dropStaleInstances($abstract);
  167. if (is_null($concrete)) {
  168. $concrete = $abstract;
  169. }
  170. // If the factory is not a Closure, it means it is just a class name which is
  171. // bound into this container to the abstract type and we will just wrap it
  172. // up inside its own Closure to give us more convenience when extending.
  173. if (! $concrete instanceof Closure) {
  174. $concrete = $this->getClosure($abstract, $concrete);
  175. }
  176. $this->bindings[$abstract] = compact('concrete', 'shared');
  177. // If the abstract type was already resolved in this container we'll fire the
  178. // rebound listener so that any objects which have already gotten resolved
  179. // can have their copy of the object updated via the listener callbacks.
  180. if ($this->resolved($abstract)) {
  181. $this->rebound($abstract);
  182. }
  183. }
  184. /**
  185. * Get the Closure to be used when building a type.
  186. *
  187. * @param string $abstract
  188. * @param string $concrete
  189. * @return \Closure
  190. */
  191. protected function getClosure($abstract, $concrete)
  192. {
  193. return function ($c, $parameters = []) use ($abstract, $concrete) {
  194. $method = ($abstract == $concrete) ? 'build' : 'make';
  195. return $c->$method($concrete, $parameters);
  196. };
  197. }
  198. /**
  199. * Add a contextual binding to the container.
  200. *
  201. * @param string $concrete
  202. * @param string $abstract
  203. * @param \Closure|string $implementation
  204. * @return void
  205. */
  206. public function addContextualBinding($concrete, $abstract, $implementation)
  207. {
  208. $this->contextual[$this->normalize($concrete)][$this->normalize($abstract)] = $this->normalize($implementation);
  209. }
  210. /**
  211. * Register a binding if it hasn't already been registered.
  212. *
  213. * @param string $abstract
  214. * @param \Closure|string|null $concrete
  215. * @param bool $shared
  216. * @return void
  217. */
  218. public function bindIf($abstract, $concrete = null, $shared = false)
  219. {
  220. if (! $this->bound($abstract)) {
  221. $this->bind($abstract, $concrete, $shared);
  222. }
  223. }
  224. /**
  225. * Register a shared binding in the container.
  226. *
  227. * @param string|array $abstract
  228. * @param \Closure|string|null $concrete
  229. * @return void
  230. */
  231. public function singleton($abstract, $concrete = null)
  232. {
  233. $this->bind($abstract, $concrete, true);
  234. }
  235. /**
  236. * Wrap a Closure such that it is shared.
  237. *
  238. * @param \Closure $closure
  239. * @return \Closure
  240. */
  241. public function share(Closure $closure)
  242. {
  243. return function ($container) use ($closure) {
  244. // We'll simply declare a static variable within the Closures and if it has
  245. // not been set we will execute the given Closures to resolve this value
  246. // and return it back to these consumers of the method as an instance.
  247. static $object;
  248. if (is_null($object)) {
  249. $object = $closure($container);
  250. }
  251. return $object;
  252. };
  253. }
  254. /**
  255. * "Extend" an abstract type in the container.
  256. *
  257. * @param string $abstract
  258. * @param \Closure $closure
  259. * @return void
  260. *
  261. * @throws \InvalidArgumentException
  262. */
  263. public function extend($abstract, Closure $closure)
  264. {
  265. $abstract = $this->normalize($abstract);
  266. if (isset($this->instances[$abstract])) {
  267. $this->instances[$abstract] = $closure($this->instances[$abstract], $this);
  268. $this->rebound($abstract);
  269. } else {
  270. $this->extenders[$abstract][] = $closure;
  271. }
  272. }
  273. /**
  274. * Register an existing instance as shared in the container.
  275. *
  276. * @param string $abstract
  277. * @param mixed $instance
  278. * @return void
  279. */
  280. public function instance($abstract, $instance)
  281. {
  282. $abstract = $this->normalize($abstract);
  283. // First, we will extract the alias from the abstract if it is an array so we
  284. // are using the correct name when binding the type. If we get an alias it
  285. // will be registered with the container so we can resolve it out later.
  286. if (is_array($abstract)) {
  287. list($abstract, $alias) = $this->extractAlias($abstract);
  288. $this->alias($abstract, $alias);
  289. }
  290. unset($this->aliases[$abstract]);
  291. // We'll check to determine if this type has been bound before, and if it has
  292. // we will fire the rebound callbacks registered with the container and it
  293. // can be updated with consuming classes that have gotten resolved here.
  294. $bound = $this->bound($abstract);
  295. $this->instances[$abstract] = $instance;
  296. if ($bound) {
  297. $this->rebound($abstract);
  298. }
  299. }
  300. /**
  301. * Assign a set of tags to a given binding.
  302. *
  303. * @param array|string $abstracts
  304. * @param array|mixed ...$tags
  305. * @return void
  306. */
  307. public function tag($abstracts, $tags)
  308. {
  309. $tags = is_array($tags) ? $tags : array_slice(func_get_args(), 1);
  310. foreach ($tags as $tag) {
  311. if (! isset($this->tags[$tag])) {
  312. $this->tags[$tag] = [];
  313. }
  314. foreach ((array) $abstracts as $abstract) {
  315. $this->tags[$tag][] = $this->normalize($abstract);
  316. }
  317. }
  318. }
  319. /**
  320. * Resolve all of the bindings for a given tag.
  321. *
  322. * @param string $tag
  323. * @return array
  324. */
  325. public function tagged($tag)
  326. {
  327. $results = [];
  328. if (isset($this->tags[$tag])) {
  329. foreach ($this->tags[$tag] as $abstract) {
  330. $results[] = $this->make($abstract);
  331. }
  332. }
  333. return $results;
  334. }
  335. /**
  336. * Alias a type to a different name.
  337. *
  338. * @param string $abstract
  339. * @param string $alias
  340. * @return void
  341. */
  342. public function alias($abstract, $alias)
  343. {
  344. $this->aliases[$alias] = $this->normalize($abstract);
  345. }
  346. /**
  347. * Extract the type and alias from a given definition.
  348. *
  349. * @param array $definition
  350. * @return array
  351. */
  352. protected function extractAlias(array $definition)
  353. {
  354. return [key($definition), current($definition)];
  355. }
  356. /**
  357. * Bind a new callback to an abstract's rebind event.
  358. *
  359. * @param string $abstract
  360. * @param \Closure $callback
  361. * @return mixed
  362. */
  363. public function rebinding($abstract, Closure $callback)
  364. {
  365. $this->reboundCallbacks[$this->normalize($abstract)][] = $callback;
  366. if ($this->bound($abstract)) {
  367. return $this->make($abstract);
  368. }
  369. }
  370. /**
  371. * Refresh an instance on the given target and method.
  372. *
  373. * @param string $abstract
  374. * @param mixed $target
  375. * @param string $method
  376. * @return mixed
  377. */
  378. public function refresh($abstract, $target, $method)
  379. {
  380. return $this->rebinding($this->normalize($abstract), function ($app, $instance) use ($target, $method) {
  381. $target->{$method}($instance);
  382. });
  383. }
  384. /**
  385. * Fire the "rebound" callbacks for the given abstract type.
  386. *
  387. * @param string $abstract
  388. * @return void
  389. */
  390. protected function rebound($abstract)
  391. {
  392. $instance = $this->make($abstract);
  393. foreach ($this->getReboundCallbacks($abstract) as $callback) {
  394. call_user_func($callback, $this, $instance);
  395. }
  396. }
  397. /**
  398. * Get the rebound callbacks for a given type.
  399. *
  400. * @param string $abstract
  401. * @return array
  402. */
  403. protected function getReboundCallbacks($abstract)
  404. {
  405. if (isset($this->reboundCallbacks[$abstract])) {
  406. return $this->reboundCallbacks[$abstract];
  407. }
  408. return [];
  409. }
  410. /**
  411. * Wrap the given closure such that its dependencies will be injected when executed.
  412. *
  413. * @param \Closure $callback
  414. * @param array $parameters
  415. * @return \Closure
  416. */
  417. public function wrap(Closure $callback, array $parameters = [])
  418. {
  419. return function () use ($callback, $parameters) {
  420. return $this->call($callback, $parameters);
  421. };
  422. }
  423. /**
  424. * Call the given Closure / class@method and inject its dependencies.
  425. *
  426. * @param callable|string $callback
  427. * @param array $parameters
  428. * @param string|null $defaultMethod
  429. * @return mixed
  430. */
  431. public function call($callback, array $parameters = [], $defaultMethod = null)
  432. {
  433. if ($this->isCallableWithAtSign($callback) || $defaultMethod) {
  434. return $this->callClass($callback, $parameters, $defaultMethod);
  435. }
  436. $dependencies = $this->getMethodDependencies($callback, $parameters);
  437. return call_user_func_array($callback, $dependencies);
  438. }
  439. /**
  440. * Determine if the given string is in Class@method syntax.
  441. *
  442. * @param mixed $callback
  443. * @return bool
  444. */
  445. protected function isCallableWithAtSign($callback)
  446. {
  447. if (! is_string($callback)) {
  448. return false;
  449. }
  450. return strpos($callback, '@') !== false;
  451. }
  452. /**
  453. * Get all dependencies for a given method.
  454. *
  455. * @param callable|string $callback
  456. * @param array $parameters
  457. * @return array
  458. */
  459. protected function getMethodDependencies($callback, array $parameters = [])
  460. {
  461. $dependencies = [];
  462. foreach ($this->getCallReflector($callback)->getParameters() as $parameter) {
  463. $this->addDependencyForCallParameter($parameter, $parameters, $dependencies);
  464. }
  465. return array_merge($dependencies, $parameters);
  466. }
  467. /**
  468. * Get the proper reflection instance for the given callback.
  469. *
  470. * @param callable|string $callback
  471. * @return \ReflectionFunctionAbstract
  472. */
  473. protected function getCallReflector($callback)
  474. {
  475. if (is_string($callback) && strpos($callback, '::') !== false) {
  476. $callback = explode('::', $callback);
  477. }
  478. if (is_array($callback)) {
  479. return new ReflectionMethod($callback[0], $callback[1]);
  480. }
  481. return new ReflectionFunction($callback);
  482. }
  483. /**
  484. * Get the dependency for the given call parameter.
  485. *
  486. * @param \ReflectionParameter $parameter
  487. * @param array $parameters
  488. * @param array $dependencies
  489. * @return mixed
  490. */
  491. protected function addDependencyForCallParameter(ReflectionParameter $parameter, array &$parameters, &$dependencies)
  492. {
  493. if (array_key_exists($parameter->name, $parameters)) {
  494. $dependencies[] = $parameters[$parameter->name];
  495. unset($parameters[$parameter->name]);
  496. } elseif ($parameter->getClass()) {
  497. $dependencies[] = $this->make($parameter->getClass()->name);
  498. } elseif ($parameter->isDefaultValueAvailable()) {
  499. $dependencies[] = $parameter->getDefaultValue();
  500. }
  501. }
  502. /**
  503. * Call a string reference to a class using Class@method syntax.
  504. *
  505. * @param string $target
  506. * @param array $parameters
  507. * @param string|null $defaultMethod
  508. * @return mixed
  509. *
  510. * @throws \InvalidArgumentException
  511. */
  512. protected function callClass($target, array $parameters = [], $defaultMethod = null)
  513. {
  514. $segments = explode('@', $target);
  515. // If the listener has an @ sign, we will assume it is being used to delimit
  516. // the class name from the handle method name. This allows for handlers
  517. // to run multiple handler methods in a single class for convenience.
  518. $method = count($segments) == 2 ? $segments[1] : $defaultMethod;
  519. if (is_null($method)) {
  520. throw new InvalidArgumentException('Method not provided.');
  521. }
  522. return $this->call([$this->make($segments[0]), $method], $parameters);
  523. }
  524. /**
  525. * Resolve the given type from the container.
  526. *
  527. * @param string $abstract
  528. * @param array $parameters
  529. * @return mixed
  530. */
  531. public function make($abstract, array $parameters = [])
  532. {
  533. $abstract = $this->getAlias($this->normalize($abstract));
  534. // If an instance of the type is currently being managed as a singleton we'll
  535. // just return an existing instance instead of instantiating new instances
  536. // so the developer can keep using the same objects instance every time.
  537. if (isset($this->instances[$abstract])) {
  538. return $this->instances[$abstract];
  539. }
  540. $concrete = $this->getConcrete($abstract);
  541. // We're ready to instantiate an instance of the concrete type registered for
  542. // the binding. This will instantiate the types, as well as resolve any of
  543. // its "nested" dependencies recursively until all have gotten resolved.
  544. if ($this->isBuildable($concrete, $abstract)) {
  545. $object = $this->build($concrete, $parameters);
  546. } else {
  547. $object = $this->make($concrete, $parameters);
  548. }
  549. // If we defined any extenders for this type, we'll need to spin through them
  550. // and apply them to the object being built. This allows for the extension
  551. // of services, such as changing configuration or decorating the object.
  552. foreach ($this->getExtenders($abstract) as $extender) {
  553. $object = $extender($object, $this);
  554. }
  555. // If the requested type is registered as a singleton we'll want to cache off
  556. // the instances in "memory" so we can return it later without creating an
  557. // entirely new instance of an object on each subsequent request for it.
  558. if ($this->isShared($abstract)) {
  559. $this->instances[$abstract] = $object;
  560. }
  561. $this->fireResolvingCallbacks($abstract, $object);
  562. $this->resolved[$abstract] = true;
  563. return $object;
  564. }
  565. /**
  566. * Get the concrete type for a given abstract.
  567. *
  568. * @param string $abstract
  569. * @return mixed $concrete
  570. */
  571. protected function getConcrete($abstract)
  572. {
  573. if (! is_null($concrete = $this->getContextualConcrete($abstract))) {
  574. return $concrete;
  575. }
  576. // If we don't have a registered resolver or concrete for the type, we'll just
  577. // assume each type is a concrete name and will attempt to resolve it as is
  578. // since the container should be able to resolve concretes automatically.
  579. if (! isset($this->bindings[$abstract])) {
  580. return $abstract;
  581. }
  582. return $this->bindings[$abstract]['concrete'];
  583. }
  584. /**
  585. * Get the contextual concrete binding for the given abstract.
  586. *
  587. * @param string $abstract
  588. * @return string|null
  589. */
  590. protected function getContextualConcrete($abstract)
  591. {
  592. if (isset($this->contextual[end($this->buildStack)][$abstract])) {
  593. return $this->contextual[end($this->buildStack)][$abstract];
  594. }
  595. }
  596. /**
  597. * Normalize the given class name by removing leading slashes.
  598. *
  599. * @param mixed $service
  600. * @return mixed
  601. */
  602. protected function normalize($service)
  603. {
  604. return is_string($service) ? ltrim($service, '\\') : $service;
  605. }
  606. /**
  607. * Get the extender callbacks for a given type.
  608. *
  609. * @param string $abstract
  610. * @return array
  611. */
  612. protected function getExtenders($abstract)
  613. {
  614. if (isset($this->extenders[$abstract])) {
  615. return $this->extenders[$abstract];
  616. }
  617. return [];
  618. }
  619. /**
  620. * Instantiate a concrete instance of the given type.
  621. *
  622. * @param string $concrete
  623. * @param array $parameters
  624. * @return mixed
  625. *
  626. * @throws \Illuminate\Contracts\Container\BindingResolutionException
  627. */
  628. public function build($concrete, array $parameters = [])
  629. {
  630. // If the concrete type is actually a Closure, we will just execute it and
  631. // hand back the results of the functions, which allows functions to be
  632. // used as resolvers for more fine-tuned resolution of these objects.
  633. if ($concrete instanceof Closure) {
  634. return $concrete($this, $parameters);
  635. }
  636. $reflector = new ReflectionClass($concrete);
  637. // If the type is not instantiable, the developer is attempting to resolve
  638. // an abstract type such as an Interface of Abstract Class and there is
  639. // no binding registered for the abstractions so we need to bail out.
  640. if (! $reflector->isInstantiable()) {
  641. if (! empty($this->buildStack)) {
  642. $previous = implode(', ', $this->buildStack);
  643. $message = "Target [$concrete] is not instantiable while building [$previous].";
  644. } else {
  645. $message = "Target [$concrete] is not instantiable.";
  646. }
  647. throw new BindingResolutionException($message);
  648. }
  649. $this->buildStack[] = $concrete;
  650. $constructor = $reflector->getConstructor();
  651. // If there are no constructors, that means there are no dependencies then
  652. // we can just resolve the instances of the objects right away, without
  653. // resolving any other types or dependencies out of these containers.
  654. if (is_null($constructor)) {
  655. array_pop($this->buildStack);
  656. return new $concrete;
  657. }
  658. $dependencies = $constructor->getParameters();
  659. // Once we have all the constructor's parameters we can create each of the
  660. // dependency instances and then use the reflection instances to make a
  661. // new instance of this class, injecting the created dependencies in.
  662. $parameters = $this->keyParametersByArgument(
  663. $dependencies, $parameters
  664. );
  665. $instances = $this->getDependencies(
  666. $dependencies, $parameters
  667. );
  668. array_pop($this->buildStack);
  669. return $reflector->newInstanceArgs($instances);
  670. }
  671. /**
  672. * Resolve all of the dependencies from the ReflectionParameters.
  673. *
  674. * @param array $parameters
  675. * @param array $primitives
  676. * @return array
  677. */
  678. protected function getDependencies(array $parameters, array $primitives = [])
  679. {
  680. $dependencies = [];
  681. foreach ($parameters as $parameter) {
  682. $dependency = $parameter->getClass();
  683. // If the class is null, it means the dependency is a string or some other
  684. // primitive type which we can not resolve since it is not a class and
  685. // we will just bomb out with an error since we have no-where to go.
  686. if (array_key_exists($parameter->name, $primitives)) {
  687. $dependencies[] = $primitives[$parameter->name];
  688. } elseif (is_null($dependency)) {
  689. $dependencies[] = $this->resolveNonClass($parameter);
  690. } else {
  691. $dependencies[] = $this->resolveClass($parameter);
  692. }
  693. }
  694. return $dependencies;
  695. }
  696. /**
  697. * Resolve a non-class hinted dependency.
  698. *
  699. * @param \ReflectionParameter $parameter
  700. * @return mixed
  701. *
  702. * @throws \Illuminate\Contracts\Container\BindingResolutionException
  703. */
  704. protected function resolveNonClass(ReflectionParameter $parameter)
  705. {
  706. if (! is_null($concrete = $this->getContextualConcrete('$'.$parameter->name))) {
  707. if ($concrete instanceof Closure) {
  708. return call_user_func($concrete, $this);
  709. } else {
  710. return $concrete;
  711. }
  712. }
  713. if ($parameter->isDefaultValueAvailable()) {
  714. return $parameter->getDefaultValue();
  715. }
  716. $message = "Unresolvable dependency resolving [$parameter] in class {$parameter->getDeclaringClass()->getName()}";
  717. throw new BindingResolutionException($message);
  718. }
  719. /**
  720. * Resolve a class based dependency from the container.
  721. *
  722. * @param \ReflectionParameter $parameter
  723. * @return mixed
  724. *
  725. * @throws \Illuminate\Contracts\Container\BindingResolutionException
  726. */
  727. protected function resolveClass(ReflectionParameter $parameter)
  728. {
  729. try {
  730. return $this->make($parameter->getClass()->name);
  731. }
  732. // If we can not resolve the class instance, we will check to see if the value
  733. // is optional, and if it is we will return the optional parameter value as
  734. // the value of the dependency, similarly to how we do this with scalars.
  735. catch (BindingResolutionException $e) {
  736. if ($parameter->isOptional()) {
  737. return $parameter->getDefaultValue();
  738. }
  739. throw $e;
  740. }
  741. }
  742. /**
  743. * If extra parameters are passed by numeric ID, rekey them by argument name.
  744. *
  745. * @param array $dependencies
  746. * @param array $parameters
  747. * @return array
  748. */
  749. protected function keyParametersByArgument(array $dependencies, array $parameters)
  750. {
  751. foreach ($parameters as $key => $value) {
  752. if (is_numeric($key)) {
  753. unset($parameters[$key]);
  754. $parameters[$dependencies[$key]->name] = $value;
  755. }
  756. }
  757. return $parameters;
  758. }
  759. /**
  760. * Register a new resolving callback.
  761. *
  762. * @param string $abstract
  763. * @param \Closure|null $callback
  764. * @return void
  765. */
  766. public function resolving($abstract, Closure $callback = null)
  767. {
  768. if ($callback === null && $abstract instanceof Closure) {
  769. $this->resolvingCallback($abstract);
  770. } else {
  771. $this->resolvingCallbacks[$this->normalize($abstract)][] = $callback;
  772. }
  773. }
  774. /**
  775. * Register a new after resolving callback for all types.
  776. *
  777. * @param string $abstract
  778. * @param \Closure|null $callback
  779. * @return void
  780. */
  781. public function afterResolving($abstract, Closure $callback = null)
  782. {
  783. if ($abstract instanceof Closure && $callback === null) {
  784. $this->afterResolvingCallback($abstract);
  785. } else {
  786. $this->afterResolvingCallbacks[$this->normalize($abstract)][] = $callback;
  787. }
  788. }
  789. /**
  790. * Register a new resolving callback by type of its first argument.
  791. *
  792. * @param \Closure $callback
  793. * @return void
  794. */
  795. protected function resolvingCallback(Closure $callback)
  796. {
  797. $abstract = $this->getFunctionHint($callback);
  798. if ($abstract) {
  799. $this->resolvingCallbacks[$abstract][] = $callback;
  800. } else {
  801. $this->globalResolvingCallbacks[] = $callback;
  802. }
  803. }
  804. /**
  805. * Register a new after resolving callback by type of its first argument.
  806. *
  807. * @param \Closure $callback
  808. * @return void
  809. */
  810. protected function afterResolvingCallback(Closure $callback)
  811. {
  812. $abstract = $this->getFunctionHint($callback);
  813. if ($abstract) {
  814. $this->afterResolvingCallbacks[$abstract][] = $callback;
  815. } else {
  816. $this->globalAfterResolvingCallbacks[] = $callback;
  817. }
  818. }
  819. /**
  820. * Get the type hint for this closure's first argument.
  821. *
  822. * @param \Closure $callback
  823. * @return mixed
  824. */
  825. protected function getFunctionHint(Closure $callback)
  826. {
  827. $function = new ReflectionFunction($callback);
  828. if ($function->getNumberOfParameters() == 0) {
  829. return;
  830. }
  831. $expected = $function->getParameters()[0];
  832. if (! $expected->getClass()) {
  833. return;
  834. }
  835. return $expected->getClass()->name;
  836. }
  837. /**
  838. * Fire all of the resolving callbacks.
  839. *
  840. * @param string $abstract
  841. * @param mixed $object
  842. * @return void
  843. */
  844. protected function fireResolvingCallbacks($abstract, $object)
  845. {
  846. $this->fireCallbackArray($object, $this->globalResolvingCallbacks);
  847. $this->fireCallbackArray(
  848. $object, $this->getCallbacksForType(
  849. $abstract, $object, $this->resolvingCallbacks
  850. )
  851. );
  852. $this->fireCallbackArray($object, $this->globalAfterResolvingCallbacks);
  853. $this->fireCallbackArray(
  854. $object, $this->getCallbacksForType(
  855. $abstract, $object, $this->afterResolvingCallbacks
  856. )
  857. );
  858. }
  859. /**
  860. * Get all callbacks for a given type.
  861. *
  862. * @param string $abstract
  863. * @param object $object
  864. * @param array $callbacksPerType
  865. *
  866. * @return array
  867. */
  868. protected function getCallbacksForType($abstract, $object, array $callbacksPerType)
  869. {
  870. $results = [];
  871. foreach ($callbacksPerType as $type => $callbacks) {
  872. if ($type === $abstract || $object instanceof $type) {
  873. $results = array_merge($results, $callbacks);
  874. }
  875. }
  876. return $results;
  877. }
  878. /**
  879. * Fire an array of callbacks with an object.
  880. *
  881. * @param mixed $object
  882. * @param array $callbacks
  883. * @return void
  884. */
  885. protected function fireCallbackArray($object, array $callbacks)
  886. {
  887. foreach ($callbacks as $callback) {
  888. $callback($object, $this);
  889. }
  890. }
  891. /**
  892. * Determine if a given type is shared.
  893. *
  894. * @param string $abstract
  895. * @return bool
  896. */
  897. public function isShared($abstract)
  898. {
  899. $abstract = $this->normalize($abstract);
  900. if (isset($this->instances[$abstract])) {
  901. return true;
  902. }
  903. if (! isset($this->bindings[$abstract]['shared'])) {
  904. return false;
  905. }
  906. return $this->bindings[$abstract]['shared'] === true;
  907. }
  908. /**
  909. * Determine if the given concrete is buildable.
  910. *
  911. * @param mixed $concrete
  912. * @param string $abstract
  913. * @return bool
  914. */
  915. protected function isBuildable($concrete, $abstract)
  916. {
  917. return $concrete === $abstract || $concrete instanceof Closure;
  918. }
  919. /**
  920. * Get the alias for an abstract if available.
  921. *
  922. * @param string $abstract
  923. * @return string
  924. */
  925. protected function getAlias($abstract)
  926. {
  927. return isset($this->aliases[$abstract]) ? $this->aliases[$abstract] : $abstract;
  928. }
  929. /**
  930. * Get the container's bindings.
  931. *
  932. * @return array
  933. */
  934. public function getBindings()
  935. {
  936. return $this->bindings;
  937. }
  938. /**
  939. * Drop all of the stale instances and aliases.
  940. *
  941. * @param string $abstract
  942. * @return void
  943. */
  944. protected function dropStaleInstances($abstract)
  945. {
  946. unset($this->instances[$abstract], $this->aliases[$abstract]);
  947. }
  948. /**
  949. * Remove a resolved instance from the instance cache.
  950. *
  951. * @param string $abstract
  952. * @return void
  953. */
  954. public function forgetInstance($abstract)
  955. {
  956. unset($this->instances[$this->normalize($abstract)]);
  957. }
  958. /**
  959. * Clear all of the instances from the container.
  960. *
  961. * @return void
  962. */
  963. public function forgetInstances()
  964. {
  965. $this->instances = [];
  966. }
  967. /**
  968. * Flush the container of all bindings and resolved instances.
  969. *
  970. * @return void
  971. */
  972. public function flush()
  973. {
  974. $this->aliases = [];
  975. $this->resolved = [];
  976. $this->bindings = [];
  977. $this->instances = [];
  978. }
  979. /**
  980. * Set the globally available instance of the container.
  981. *
  982. * @return static
  983. */
  984. public static function getInstance()
  985. {
  986. return static::$instance;
  987. }
  988. /**
  989. * Set the shared instance of the container.
  990. *
  991. * @param \Illuminate\Contracts\Container\Container $container
  992. * @return void
  993. */
  994. public static function setInstance(ContainerContract $container)
  995. {
  996. static::$instance = $container;
  997. }
  998. /**
  999. * Determine if a given offset exists.
  1000. *
  1001. * @param string $key
  1002. * @return bool
  1003. */
  1004. public function offsetExists($key)
  1005. {
  1006. return $this->bound($key);
  1007. }
  1008. /**
  1009. * Get the value at a given offset.
  1010. *
  1011. * @param string $key
  1012. * @return mixed
  1013. */
  1014. public function offsetGet($key)
  1015. {
  1016. return $this->make($key);
  1017. }
  1018. /**
  1019. * Set the value at a given offset.
  1020. *
  1021. * @param string $key
  1022. * @param mixed $value
  1023. * @return void
  1024. */
  1025. public function offsetSet($key, $value)
  1026. {
  1027. // If the value is not a Closure, we will make it one. This simply gives
  1028. // more "drop-in" replacement functionality for the Pimple which this
  1029. // container's simplest functions are base modeled and built after.
  1030. if (! $value instanceof Closure) {
  1031. $value = function () use ($value) {
  1032. return $value;
  1033. };
  1034. }
  1035. $this->bind($key, $value);
  1036. }
  1037. /**
  1038. * Unset the value at a given offset.
  1039. *
  1040. * @param string $key
  1041. * @return void
  1042. */
  1043. public function offsetUnset($key)
  1044. {
  1045. $key = $this->normalize($key);
  1046. unset($this->bindings[$key], $this->instances[$key], $this->resolved[$key]);
  1047. }
  1048. /**
  1049. * Dynamically access container services.
  1050. *
  1051. * @param string $key
  1052. * @return mixed
  1053. */
  1054. public function __get($key)
  1055. {
  1056. return $this[$key];
  1057. }
  1058. /**
  1059. * Dynamically set container services.
  1060. *
  1061. * @param string $key
  1062. * @param mixed $value
  1063. * @return void
  1064. */
  1065. public function __set($key, $value)
  1066. {
  1067. $this[$key] = $value;
  1068. }
  1069. }