Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

158 lines
5.4KB

  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\di;
  8. use Yii;
  9. use yii\base\InvalidConfigException;
  10. /**
  11. * Instance represents a reference to a named object in a dependency injection (DI) container or a service locator.
  12. *
  13. * You may use [[get()]] to obtain the actual object referenced by [[id]].
  14. *
  15. * Instance is mainly used in two places:
  16. *
  17. * - When configuring a dependency injection container, you use Instance to reference a class name, interface name
  18. * or alias name. The reference can later be resolved into the actual object by the container.
  19. * - In classes which use service locator to obtain dependent objects.
  20. *
  21. * The following example shows how to configure a DI container with Instance:
  22. *
  23. * ```php
  24. * $container = new \yii\di\Container;
  25. * $container->set('cache', 'yii\caching\DbCache', Instance::of('db'));
  26. * $container->set('db', [
  27. * 'class' => 'yii\db\Connection',
  28. * 'dsn' => 'sqlite:path/to/file.db',
  29. * ]);
  30. * ```
  31. *
  32. * And the following example shows how a class retrieves a component from a service locator:
  33. *
  34. * ```php
  35. * class DbCache extends Cache
  36. * {
  37. * public $db = 'db';
  38. *
  39. * public function init()
  40. * {
  41. * parent::init();
  42. * $this->db = Instance::ensure($this->db, 'yii\db\Connection');
  43. * }
  44. * }
  45. * ```
  46. *
  47. * @author Qiang Xue <qiang.xue@gmail.com>
  48. * @since 2.0
  49. */
  50. class Instance
  51. {
  52. /**
  53. * @var string the component ID, class name, interface name or alias name
  54. */
  55. public $id;
  56. /**
  57. * Constructor.
  58. * @param string $id the component ID
  59. */
  60. protected function __construct($id)
  61. {
  62. $this->id = $id;
  63. }
  64. /**
  65. * Creates a new Instance object.
  66. * @param string $id the component ID
  67. * @return Instance the new Instance object.
  68. */
  69. public static function of($id)
  70. {
  71. return new static($id);
  72. }
  73. /**
  74. * Resolves the specified reference into the actual object and makes sure it is of the specified type.
  75. *
  76. * The reference may be specified as a string or an Instance object. If the former,
  77. * it will be treated as a component ID, a class/interface name or an alias, depending on the container type.
  78. *
  79. * If you do not specify a container, the method will first try `Yii::$app` followed by `Yii::$container`.
  80. *
  81. * For example,
  82. *
  83. * ```php
  84. * use yii\db\Connection;
  85. *
  86. * // returns Yii::$app->db
  87. * $db = Instance::ensure('db', Connection::className());
  88. * // returns an instance of Connection using the given configuration
  89. * $db = Instance::ensure(['dsn' => 'sqlite:path/to/my.db'], Connection::className());
  90. * ```
  91. *
  92. * @param object|string|array|static $reference an object or a reference to the desired object.
  93. * You may specify a reference in terms of a component ID or an Instance object.
  94. * Starting from version 2.0.2, you may also pass in a configuration array for creating the object.
  95. * If the "class" value is not specified in the configuration array, it will use the value of `$type`.
  96. * @param string $type the class/interface name to be checked. If null, type check will not be performed.
  97. * @param ServiceLocator|Container $container the container. This will be passed to [[get()]].
  98. * @return object the object referenced by the Instance, or `$reference` itself if it is an object.
  99. * @throws InvalidConfigException if the reference is invalid
  100. */
  101. public static function ensure($reference, $type = null, $container = null)
  102. {
  103. if ($reference instanceof $type) {
  104. return $reference;
  105. } elseif (is_array($reference)) {
  106. $class = isset($reference['class']) ? $reference['class'] : $type;
  107. if (!$container instanceof Container) {
  108. $container = Yii::$container;
  109. }
  110. unset($reference['class']);
  111. return $container->get($class, [], $reference);
  112. } elseif (empty($reference)) {
  113. throw new InvalidConfigException('The required component is not specified.');
  114. }
  115. if (is_string($reference)) {
  116. $reference = new static($reference);
  117. }
  118. if ($reference instanceof self) {
  119. $component = $reference->get($container);
  120. if ($component instanceof $type || $type === null) {
  121. return $component;
  122. } else {
  123. throw new InvalidConfigException('"' . $reference->id . '" refers to a ' . get_class($component) . " component. $type is expected.");
  124. }
  125. }
  126. $valueType = is_object($reference) ? get_class($reference) : gettype($reference);
  127. throw new InvalidConfigException("Invalid data type: $valueType. $type is expected.");
  128. }
  129. /**
  130. * Returns the actual object referenced by this Instance object.
  131. * @param ServiceLocator|Container $container the container used to locate the referenced object.
  132. * If null, the method will first try `Yii::$app` then `Yii::$container`.
  133. * @return object the actual object referenced by this Instance object.
  134. */
  135. public function get($container = null)
  136. {
  137. if ($container) {
  138. return $container->get($this->id);
  139. }
  140. if (Yii::$app && Yii::$app->has($this->id)) {
  141. return Yii::$app->get($this->id);
  142. } else {
  143. return Yii::$container->get($this->id);
  144. }
  145. }
  146. }