ioc.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. <?php namespace Laravel; use Closure;
  2. class IoC {
  3. /**
  4. * The registered dependencies.
  5. *
  6. * @var array
  7. */
  8. public static $registry = array();
  9. /**
  10. * The resolved singleton instances.
  11. *
  12. * @var array
  13. */
  14. public static $singletons = array();
  15. /**
  16. * Register an object and its resolver.
  17. *
  18. * @param string $name
  19. * @param mixed $resolver
  20. * @param bool $singleton
  21. * @return void
  22. */
  23. public static function register($name, $resolver = null, $singleton = false)
  24. {
  25. if (is_null($resolver)) $resolver = $name;
  26. static::$registry[$name] = compact('resolver', 'singleton');
  27. }
  28. /**
  29. * Determine if an object has been registered in the container.
  30. *
  31. * @param string $name
  32. * @return bool
  33. */
  34. public static function registered($name)
  35. {
  36. return array_key_exists($name, static::$registry);
  37. }
  38. /**
  39. * Register an object as a singleton.
  40. *
  41. * Singletons will only be instantiated the first time they are resolved.
  42. *
  43. * @param string $name
  44. * @param Closure $resolver
  45. * @return void
  46. */
  47. public static function singleton($name, $resolver = null)
  48. {
  49. static::register($name, $resolver, true);
  50. }
  51. /**
  52. * Register an existing instance as a singleton.
  53. *
  54. * <code>
  55. * // Register an instance as a singleton in the container
  56. * IoC::instance('mailer', new Mailer);
  57. * </code>
  58. *
  59. * @param string $name
  60. * @param mixed $instance
  61. * @return void
  62. */
  63. public static function instance($name, $instance)
  64. {
  65. static::$singletons[$name] = $instance;
  66. }
  67. /**
  68. * Resolve a given type to an instance.
  69. *
  70. * <code>
  71. * // Get an instance of the "mailer" object registered in the container
  72. * $mailer = IoC::resolve('mailer');
  73. *
  74. * // Get an instance of the "mailer" object and pass parameters to the resolver
  75. * $mailer = IoC::resolve('mailer', array('test'));
  76. * </code>
  77. *
  78. * @param string $type
  79. * @param array $parameters
  80. * @return mixed
  81. */
  82. public static function resolve($type, $parameters = array())
  83. {
  84. // If an instance of the type is currently being managed as a singleton, we will
  85. // just return the existing instance instead of instantiating a fresh instance
  86. // so the developer can keep re-using the exact same object instance from us.
  87. if (isset(static::$singletons[$type]))
  88. {
  89. return static::$singletons[$type];
  90. }
  91. // If we don't have a registered resolver or concrete for the type, we'll just
  92. // assume the type is the concrete name and will attempt to resolve it as is
  93. // since the container should be able to resolve concretes automatically.
  94. if ( ! isset(static::$registry[$type]))
  95. {
  96. $concrete = $type;
  97. }
  98. else
  99. {
  100. $concrete = array_get(static::$registry[$type], 'resolver', $type);
  101. }
  102. // We're ready to instantiate an instance of the concrete type registered for
  103. // the binding. This will instantiate the type, as well as resolve any of
  104. // its nested dependencies recursively until they are each resolved.
  105. if ($concrete == $type or $concrete instanceof Closure)
  106. {
  107. $object = static::build($concrete, $parameters);
  108. }
  109. else
  110. {
  111. $object = static::resolve($concrete);
  112. }
  113. // If the requested type is registered as a singleton, we want to cache off
  114. // the instance in memory so we can return it later without creating an
  115. // entirely new instances of the object on each subsequent request.
  116. if (isset(static::$registry[$type]['singleton']) && static::$registry[$type]['singleton'] === true)
  117. {
  118. static::$singletons[$type] = $object;
  119. }
  120. Event::fire('laravel.resolving', array($type, $object));
  121. return $object;
  122. }
  123. /**
  124. * Instantiate an instance of the given type.
  125. *
  126. * @param string $type
  127. * @param array $parameters
  128. * @return mixed
  129. */
  130. protected static function build($type, $parameters = array())
  131. {
  132. // If the concrete type is actually a Closure, we will just execute it and
  133. // hand back the results of the function, which allows functions to be
  134. // used as resolvers for more fine-tuned resolution of the objects.
  135. if ($type instanceof Closure)
  136. {
  137. return call_user_func_array($type, $parameters);
  138. }
  139. $reflector = new \ReflectionClass($type);
  140. // If the type is not instantiable, the developer is attempting to resolve
  141. // an abstract type such as an Interface of an Abstract Class and there is
  142. // no binding registered for the abstraction so we need to bail out.
  143. if ( ! $reflector->isInstantiable())
  144. {
  145. throw new \Exception("Resolution target [$type] is not instantiable.");
  146. }
  147. $constructor = $reflector->getConstructor();
  148. // If there is no constructor, that means there are no dependencies and
  149. // we can just resolve an instance of the object right away without
  150. // resolving any other types or dependencies from the container.
  151. if (is_null($constructor))
  152. {
  153. return new $type;
  154. }
  155. $dependencies = static::dependencies($constructor->getParameters());
  156. return $reflector->newInstanceArgs($dependencies);
  157. }
  158. /**
  159. * Resolve all of the dependencies from the ReflectionParameters.
  160. *
  161. * @param array $parameters
  162. * @return array
  163. */
  164. protected static function dependencies($parameters)
  165. {
  166. $dependencies = array();
  167. foreach ($parameters as $parameter)
  168. {
  169. $dependency = $parameter->getClass();
  170. // If the class is null, it means the dependency is a string or some other
  171. // primitive type, which we can not resolve since it is not a class and
  172. // we'll just bomb out with an error since we have nowhere to go.
  173. if (is_null($dependency))
  174. {
  175. throw new \Exception("Unresolvable dependency resolving [$parameter].");
  176. }
  177. $dependencies[] = static::resolve($dependency->name);
  178. }
  179. return (array) $dependencies;
  180. }
  181. }