1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
|
4
|
|
|
namespace yii\di; |
5
|
|
|
|
6
|
|
|
use Psr\Container\ContainerInterface; |
7
|
|
|
use yii\di\contracts\DependencyInterface; |
8
|
|
|
use yii\di\dependencies\NamedDependency; |
9
|
|
|
use yii\di\dependencies\ValueDependency; |
10
|
|
|
use yii\di\exceptions\InvalidConfigException; |
11
|
|
|
use yii\di\exceptions\NotInstantiableException; |
12
|
|
|
use yii\di\resolvers\ClassNameResolver; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* Class Definition represents a definition in a container |
16
|
|
|
* @package yii\di |
17
|
|
|
*/ |
18
|
|
|
class Definition |
19
|
|
|
{ |
20
|
|
|
private static $dependencies = []; |
21
|
|
|
|
22
|
|
|
private const TYPE_CALLABLE = 'callable'; |
23
|
|
|
private const TYPE_ARRAY = 'array'; |
24
|
|
|
private const TYPE_RESOLVABLE = 'resolvable'; |
25
|
|
|
private const TYPE_VALUE = 'value'; |
26
|
|
|
private $type; |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* @var array|DependencyInterface |
30
|
|
|
*/ |
31
|
|
|
private $config; |
32
|
|
|
|
33
|
|
|
private function __construct($config, string $type) |
34
|
|
|
{ |
35
|
|
|
$this->type = $type; |
36
|
|
|
$this->config = $config; |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
public static function normalize($config): self |
40
|
|
|
{ |
41
|
|
|
if ($config instanceof self) { |
42
|
|
|
return $config; |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
if (is_string($config)) { |
46
|
|
|
return new self(['__class' => $config], self::TYPE_ARRAY); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
if (is_array($config) |
50
|
|
|
&& !isset($config[0], $config[1]) |
51
|
|
|
&& isset($config['__class']) |
52
|
|
|
) { |
53
|
|
|
return new self($config, self::TYPE_ARRAY); |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
if (\is_callable($config)) { |
57
|
|
|
return new self($config, self::TYPE_CALLABLE); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
if ($config instanceof DependencyInterface) { |
61
|
|
|
return new self($config, self::TYPE_RESOLVABLE); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
if (is_object($config)) { |
65
|
|
|
return new self($config, self::TYPE_VALUE); |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
throw new InvalidConfigException('Invalid definition:' . var_export($config, true)); |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* @param array $definition |
73
|
|
|
* @param ContainerInterface $rootContainer |
74
|
|
|
*/ |
75
|
|
|
private function resolveArray(array $config, ContainerInterface $rootContainer) |
76
|
|
|
{ |
77
|
|
|
if (empty($config['__class'])) { |
78
|
|
|
throw new NotInstantiableException(var_export($config, true)); |
79
|
|
|
} |
80
|
|
|
$class = $config['__class']; |
81
|
|
|
unset($config['__class']); |
82
|
|
|
|
83
|
|
|
$dependencies = $this->getDependencies($class); |
84
|
|
|
|
85
|
|
|
if (isset($config['__construct()'])) { |
86
|
|
|
foreach (array_values($config['__construct()']) as $index => $param) { |
87
|
|
|
if (!$param instanceof Reference) { |
88
|
|
|
$dependencies[$index] = new ValueDependency($param); |
89
|
|
|
} else { |
90
|
|
|
$dependencies[$index] = new NamedDependency($param->getId(), false); |
91
|
|
|
} |
92
|
|
|
} |
93
|
|
|
unset($config['__construct()']); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
$resolved = []; |
97
|
|
|
/** @var DependencyInterface $dependency */ |
98
|
|
|
foreach ($dependencies as $dependency) { |
99
|
|
|
$resolved[] = $dependency->resolve($rootContainer); |
100
|
|
|
} |
101
|
|
|
$object = new $class(...$resolved); |
102
|
|
|
|
103
|
|
|
$this->configure($object, $config, $rootContainer); |
|
|
|
|
104
|
|
|
return $object; |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* @param Container $container |
109
|
|
|
* @return mixed|object |
110
|
|
|
* @throws NotInstantiableException |
111
|
|
|
*/ |
112
|
|
|
public function resolve(ContainerInterface $rootContainer) |
113
|
|
|
{ |
114
|
|
|
switch ($this->type) { |
115
|
|
|
case self::TYPE_CALLABLE: |
116
|
|
|
return call_user_func($this->config, $rootContainer); |
|
|
|
|
117
|
|
|
case self::TYPE_ARRAY: |
118
|
|
|
return $this->resolveArray($this->config, $rootContainer); |
|
|
|
|
119
|
|
|
case self::TYPE_VALUE: |
120
|
|
|
return $this->config; |
121
|
|
|
case self::TYPE_RESOLVABLE: |
122
|
|
|
return $this->config->resolve($rootContainer); |
123
|
|
|
} |
124
|
|
|
|
125
|
|
|
throw new \RuntimeException('Attempted to resolve invalid definition of type: ' . $this->type); |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Configures an object with the given configuration. |
130
|
|
|
* @deprecated Not recommended for explicit use. Added only to support Yii 2.0 behavior. |
131
|
|
|
* @param object $object the object to be configured |
132
|
|
|
* @param iterable $config property values and methods to call |
133
|
|
|
* @param ContainerInterface $container |
134
|
|
|
* @return object the object itself |
135
|
|
|
*/ |
136
|
|
|
private function configure($object, iterable $config, ContainerInterface $container) |
137
|
|
|
{ |
138
|
|
|
foreach ($config as $action => $arguments) { |
139
|
|
|
if (substr($action, -2) === '()') { |
140
|
|
|
// method call |
141
|
|
|
\call_user_func_array([$object, substr($action, 0, -2)], $arguments); |
142
|
|
|
} else { |
143
|
|
|
// property |
144
|
|
|
if ($arguments instanceof DependencyInterface) { |
145
|
|
|
$arguments = $arguments->resolve($container); |
146
|
|
|
} |
147
|
|
|
$object->$action = $arguments; |
148
|
|
|
} |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
return $object; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* Returns the dependencies of the specified class. |
156
|
|
|
* @param string $class class name, interface name or alias name |
157
|
|
|
* @return DependencyInterface[] the dependencies of the specified class. |
158
|
|
|
* @throws InvalidConfigException |
159
|
|
|
* @throws NotInstantiableException |
160
|
|
|
* @internal |
161
|
|
|
*/ |
162
|
|
|
private function getDependencies(string $class): array |
163
|
|
|
{ |
164
|
|
|
if (!isset($this->dependencies[$class])) { |
165
|
|
|
// For now use hard coded resolver. |
166
|
|
|
$resolver = new ClassNameResolver(); |
167
|
|
|
|
168
|
|
|
self::$dependencies[$class] = $resolver->resolveConstructor($class); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
return self::$dependencies[$class]; |
172
|
|
|
} |
173
|
|
|
} |
174
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.