1
|
|
|
<?php declare(strict_types=1); |
2
|
|
|
|
3
|
|
|
namespace League\Container; |
4
|
|
|
|
5
|
|
|
use League\Container\Definition\{DefinitionAggregate, DefinitionInterface, DefinitionAggregateInterface}; |
6
|
|
|
use League\Container\Inflector\{InflectorAggregate, InflectorInterface, InflectorAggregateInterface}; |
7
|
|
|
use League\Container\ServiceProvider\{ServiceProviderAggregate, ServiceProviderAggregateInterface}; |
8
|
|
|
use Psr\Container\ContainerInterface; |
9
|
|
|
|
10
|
|
|
class Container implements ContainerInterface |
11
|
|
|
{ |
12
|
|
|
/** |
13
|
|
|
* @var \League\Container\Definition\DefinitionAggregateInterface |
14
|
|
|
*/ |
15
|
|
|
protected $definitions; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* @var \League\Container\ServiceProvider\ServiceProviderAggregateInterface |
19
|
|
|
*/ |
20
|
|
|
protected $providers; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @var \League\Container\Inflector\InflectorAggregateInterface |
24
|
|
|
*/ |
25
|
|
|
protected $inflectors; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* @var \Psr\Container\ContainerInterface[] |
29
|
|
|
*/ |
30
|
|
|
protected $delegates = []; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* Construct. |
34
|
|
|
* |
35
|
|
|
* @param \League\Container\Definition\DefinitionAggregateInterface|null $definitions |
36
|
|
|
* @param \League\Container\ServiceProvider\ServiceProviderAggregateInterface|null $providers |
37
|
|
|
* @param \League\Container\Inflector\InflectorAggregateInterface|null $inflectors |
38
|
|
|
*/ |
39
|
|
|
public function __construct( |
40
|
|
|
DefinitionAggregateInterface $definitions = null, |
41
|
|
|
ServiceProviderAggregateInterface $providers = null, |
42
|
|
|
InflectorAggregateInterface $inflectors = null |
43
|
|
|
) { |
44
|
|
|
$this->definitions = $definitions ?? (new DefinitionAggregate)->setContainer($this); |
45
|
|
|
$this->providers = $providers ?? (new ServiceProviderAggregate)->setContainer($this); |
46
|
|
|
$this->inflectors = $inflectors ?? (new InflectorAggregate)->setContainer($this); |
47
|
|
|
} |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Add an item to the container. |
51
|
|
|
* |
52
|
|
|
* @param string $id |
53
|
|
|
* @param mixed $concrete |
54
|
|
|
* @param boolean $shared |
55
|
|
|
* |
56
|
|
|
* @return \League\Container\Definition\DefinitionInterface |
57
|
|
|
*/ |
58
|
|
|
public function add(string $id, $concrete = null, bool $shared = false): DefinitionInterface |
59
|
|
|
{ |
60
|
57 |
|
$concrete = $concrete ?? $id; |
61
|
|
|
|
62
|
|
|
return $this->definitions->add($id, $concrete, $shared); |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
57 |
|
* Get a definition to extend. |
67
|
56 |
|
* |
68
|
39 |
|
* @param string $id [description] |
69
|
|
|
* |
70
|
57 |
|
* @return \League\Container\Definition\DefinitionInterface |
71
|
57 |
|
*/ |
72
|
38 |
|
public function extend(string $id): DefinitionInterface |
73
|
|
|
{ |
74
|
57 |
|
if ($this->providers->provides($id)) { |
75
|
57 |
|
$this->providers->register($id); |
76
|
38 |
|
} |
77
|
57 |
|
|
78
|
|
|
if ($this->definitions->has($id)) { |
79
|
|
|
return $this->definitions->getDefinition($id); |
80
|
|
|
} |
81
|
|
|
|
82
|
45 |
|
throw new NotFoundException( |
83
|
|
|
sprintf('Unable to extend alias (%s) as it is not being managed as a definition', $alias) |
84
|
|
|
); |
85
|
45 |
|
} |
86
|
21 |
|
|
87
|
21 |
|
/** |
88
|
12 |
|
* Add a service provider. |
89
|
|
|
* |
90
|
12 |
|
* @param \League\Container\ServiceProvider\ServiceProviderInterface|string $provider |
91
|
|
|
* |
92
|
|
|
* @return self |
93
|
9 |
|
*/ |
94
|
|
|
public function addServiceProvider($provider): self |
95
|
6 |
|
{ |
96
|
|
|
$this->providers->add($provider); |
97
|
|
|
|
98
|
|
|
return $this; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
21 |
|
* {@inheritdoc} |
103
|
|
|
*/ |
104
|
21 |
|
public function get($id, array $args = [], bool $new = false) |
105
|
15 |
|
{ |
106
|
|
|
if ($this->definitions->has($id)) { |
107
|
|
|
$resolved = $this->definitions->resolve($id, $args, $new); |
108
|
9 |
|
return $this->inflectors->inflect($resolved); |
109
|
3 |
|
} |
110
|
|
|
|
111
|
|
|
if ($this->providers->provides($id)) { |
112
|
9 |
|
$this->providers->register($id); |
113
|
|
|
return $this->get($id, $args, $new); |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
foreach ($this->delegates as $delegate) { |
117
|
|
|
if ($delegate->has($id)) { |
118
|
|
|
$resolved = $delegate->get($id, $args); |
|
|
|
|
119
|
|
|
return $this->inflectors->inflect($resolved); |
120
|
|
|
} |
121
|
|
|
} |
122
|
51 |
|
|
123
|
|
|
throw new NotFoundException(sprintf('Alias (%s) is not being managed by the container or delegates', $id)); |
124
|
51 |
|
} |
125
|
|
|
|
126
|
51 |
|
/** |
127
|
|
|
* {@inheritdoc} |
128
|
|
|
*/ |
129
|
|
|
public function has($id): bool |
130
|
|
|
{ |
131
|
|
|
if ($this->definitions->has($id)) { |
132
|
45 |
|
return true; |
133
|
|
|
} |
134
|
45 |
|
|
135
|
45 |
|
if ($this->providers->provides($id)) { |
136
|
45 |
|
return true; |
137
|
|
|
} |
138
|
45 |
|
|
139
|
3 |
|
foreach ($this->delegates as $delegate) { |
140
|
2 |
|
if ($delegate->has($id)) { |
141
|
|
|
return true; |
142
|
45 |
|
} |
143
|
|
|
} |
144
|
45 |
|
|
145
|
39 |
|
return false; |
146
|
18 |
|
} |
147
|
12 |
|
|
148
|
33 |
|
/** |
149
|
|
|
* Allows for manipulation of specific types on resolution. |
150
|
|
|
* |
151
|
39 |
|
* @param string $type |
152
|
|
|
* @param callable|null $callback |
153
|
|
|
* |
154
|
|
|
* @return \League\Container\Inflector\InflectorInterface |
155
|
6 |
|
*/ |
156
|
6 |
|
public function inflector(string $type, callable $callback = null): InflectorInterface |
157
|
|
|
{ |
158
|
|
|
return $this->inflectors->add($type, $callback); |
159
|
|
|
} |
160
|
|
|
|
161
|
33 |
|
/** |
162
|
|
|
* Delegate a backup container to be checked for services if it |
163
|
33 |
|
* cannot be resolved via this container. |
164
|
|
|
* |
165
|
|
|
* @param \Psr\Container\ContainerInterface $container |
166
|
|
|
* |
167
|
|
|
* @return self |
168
|
|
|
*/ |
169
|
12 |
|
public function delegate(ContainerInterface $container): self |
170
|
|
|
{ |
171
|
12 |
|
$this->delegates[] = $container; |
172
|
|
|
|
173
|
12 |
|
if ($container instanceof ContainerAwareInterface) { |
174
|
|
|
$container->setContainer($this); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
return $this; |
178
|
|
|
} |
179
|
|
|
} |
180
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignore
PhpDoc annotation to the duplicate definition and it will be ignored.