GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Container   A
last analyzed

Complexity

Total Complexity 41

Size/Duplication

Total Lines 267
Duplicated Lines 5.99 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 41
lcom 1
cbo 1
dl 16
loc 267
ccs 98
cts 98
cp 1
rs 9.1199
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A set() 0 11 3
A unset() 0 7 1
A alias() 0 6 1
A unalias() 0 4 1
A has() 0 8 2
A hasInstance() 8 8 2
A get() 0 25 5
A getNew() 0 15 4
A getValueInstance() 0 12 3
A destroyInstance() 8 8 2
A destroyAllInstances() 0 8 1
A __call() 0 24 5
A resolveInstance() 0 17 3
B resolveParameters() 0 33 8

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Container often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Container, and based on these observations, apply Extract Interface, too.

1
<?php declare(strict_types=1);
2
/**
3
 * Starlit App.
4
 *
5
 * @copyright Copyright (c) 2016 Starweb AB
6
 * @license   BSD 3-Clause
7
 */
8
9
namespace Starlit\App\Container;
10
11
use Psr\Container\ContainerInterface;
12
13
class Container implements ContainerInterface
14
{
15
    /**
16
     * @var array
17
     */
18
    private $dicValues = [];
19
20
    /**
21
     * @var array
22
     */
23
    private $aliases = [];
24
25
    /**
26
     * @var array
27
     */
28
    private $dicObjects = [];
29
30
    /**
31
     * Set a DIC value.
32
     *
33
     * Wrap objects provided in a closure for lazy loading.
34
     *
35
     * @param string $key
36
     * @param mixed  $value
37
     * @return ContainerInterface
38
     */
39 25
    public function set(string $key, $value): ContainerInterface
40
    {
41 25
        if (!(\is_string($value) || \is_object($value))) {
42 1
            throw new \InvalidArgumentException('Value must be a class name, an object instance, or a callable');
43
        }
44
45 24
        $this->dicValues[$key] = $value;
46 24
        unset($this->dicObjects[$key]); // In case an object instance was stored for sharing
47
48 24
        return $this;
49
    }
50
51 1
    public function unset(string $key): void
52
    {
53
        unset(
54 1
            $this->dicValues[$key],
55 1
            $this->dicObjects[$key]
56
        );
57 1
    }
58
59 23
    public function alias(string $alias, string $key): ContainerInterface
60
    {
61 23
        $this->aliases[$alias] = $key;
62
63 23
        return $this;
64
    }
65
66 1
    public function unalias(string $alias): void
67
    {
68 1
        unset($this->aliases[$alias]);
69 1
    }
70
71
    /**
72
     * @inheritdoc
73
     */
74 4
    public function has($key): bool
75
    {
76 4
        if (isset($this->aliases[$key])) {
77 1
            $key = $this->aliases[$key];
78
        }
79
80 4
        return isset($this->dicValues[$key]);
81
    }
82
83 4 View Code Duplication
    public function hasInstance(string $key): bool
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
84
    {
85 4
        if (isset($this->aliases[$key])) {
86 1
            $key = $this->aliases[$key];
87
        }
88
89 4
        return isset($this->dicObjects[$key]);
90
    }
91
92
    /**
93
     * @inheritdoc
94
     */
95 36
    public function get($key)
96
    {
97 36
        if (isset($this->aliases[$key])) {
98 1
            $key = $this->aliases[$key];
99
        }
100
101
        // Get already instantiated object if it exist
102 36
        if (isset($this->dicObjects[$key])) {
103 3
            return $this->dicObjects[$key];
104
        }
105
106
        try {
107 36
            if (isset($this->dicValues[$key])) {
108 25
                $instance = $this->getValueInstance($key);
109
            } else {
110 36
                $instance = $this->resolveInstance($key);
111
            }
112 4
        } catch (\ReflectionException $e) {
113 4
            throw new NotFoundException(sprintf('Key "%s" could not be resolved.', $key));
114
        }
115
116 33
        $this->dicObjects[$key] = $instance;
117
118 33
        return $this->dicObjects[$key];
119
    }
120
121
    /**
122
     * Get a new instance of a DIC object
123
     *
124
     * @param string $key
125
     * @return mixed
126
     */
127 7
    public function getNew(string $key)
128
    {
129 7
        if (isset($this->aliases[$key])) {
130 1
            $key = $this->aliases[$key];
131
        }
132
133
        try {
134 7
            if (isset($this->dicValues[$key])) {
135 4
                return $this->getValueInstance($key);
136
            }
137 3
            return $this->resolveInstance($key);
138 3
        } catch (\ReflectionException $e) {
139 3
            throw new NotFoundException(sprintf('Key "%s" could not be resolved.', $key));
140
        }
141
    }
142
143 25
    private function getValueInstance(string $key)
144
    {
145 25
        $value = $this->dicValues[$key];
146 25
        if (\is_object($value)) {
147
            // Is it an invokable? (closure/anonymous function)
148 24
            if (\method_exists($value, '__invoke')) {
149 23
                return $value($this);
150
            }
151 7
            return $value;
152
        }
153 2
        return $this->resolveInstance($value);
154
    }
155
156
    /**
157
     * Destroy a DIC object instance.
158
     *
159
     * Will force a new object to be created on next call.
160
     *
161
     * @param string $key
162
     */
163 3 View Code Duplication
    public function destroyInstance(string $key): void
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
164
    {
165 3
        if (isset($this->aliases[$key])) {
166 1
            $key = $this->aliases[$key];
167
        }
168
169 3
        unset($this->dicObjects[$key]);
170 3
    }
171
172 2
    public function destroyAllInstances(): void
173
    {
174 2
        $this->dicObjects = [];
175
176
        // To make sure objects (like database connections) are destructed properly. PHP might not destruct objects
177
        // until the end of execution otherwise.
178 2
        \gc_collect_cycles();
179 2
    }
180
181
    /**
182
     * Magic method to get or set DIC values.
183
     *
184
     * @param string $name
185
     * @param array  $arguments
186
     * @return mixed
187
     */
188 8
    public function __call(string $name, array $arguments)
189
    {
190
        // getNew followed by an upper letter like getNewApple()
191 8
        if (\preg_match('/^getNew([A-Z].*)/', $name, $matches)) {
192 1
            $key = \lcfirst($matches[1]);
193
194 1
            return $this->getNew($key);
195 7
        } elseif (\strpos($name, 'get') === 0) {
196 2
            $key = \lcfirst(\substr($name, 3));
197
198 2
            return $this->get($key);
199 6
        } elseif (\strpos($name, 'set') === 0) {
200 4
            $argumentCount = count($arguments);
201 4
            if ($argumentCount !== 1) {
202 2
                throw new \BadMethodCallException("Invalid argument count[{$argumentCount}] for application {$name}()");
203
            }
204
205 2
            $key = \lcfirst(substr($name, 3));
206
207 2
            return $this->set($key, $arguments[0]);
208
        } else {
209 2
            throw new \BadMethodCallException("No application method named {$name}()");
210
        }
211
    }
212
213
    /**
214
     * Instantiate an object of named class, recursively resolving dependencies
215
     *
216
     * @param string $className Fully qualified class name
217
     * @return mixed
218
     * @throws \ReflectionException
219
     */
220 16
    private function resolveInstance(string $className)
221
    {
222 16
        $class = new \ReflectionClass($className);
223
224 13
        if (!$class->isInstantiable()) {
225 3
            throw new \ReflectionException(sprintf('Class %s cannot be instantiated', $className));
226
        }
227
228 10
        $parameterValues = [];
229 10
        if (($constructor = $class->getConstructor())) {
230 1
            $parameterValues = $this->resolveParameters(
231 1
                $constructor->getParameters()
232
            );
233
        }
234
235 10
        return $class->newInstanceArgs($parameterValues);
236
    }
237
238
    /**
239
     * Recursively resolve function parameters using type hints
240
     *
241
     * @param \ReflectionParameter[] $parameters
242
     * @param array $predefinedValues
243
     * @return array
244
     * @throws \ReflectionException
245
     */
246 12
    public function resolveParameters(array $parameters, array $predefinedValues = []): array
247
    {
248 12
        $values = [];
249
250
        /**
251
         * @var \ReflectionParameter $parameter
252
         */
253 12
        foreach ($parameters as $parameter) {
254 12
            if (\array_key_exists($parameter->getName(), $predefinedValues)) {
255 8
                if ($parameter->hasType() && $parameter->getType()->isBuiltin()) {
256 6
                    \settype($predefinedValues[$parameter->getName()], $parameter->getType()->getName());
257
                }
258 8
                $values[] = $predefinedValues[$parameter->getName()];
259
            } else {
260 11
                if (($parameterClass = $parameter->getClass())) {
261
                    try {
262 10
                        $values[] = $this->get($parameterClass->getName());
263
                    }
264 2
                    catch (NotFoundException $e) { // We're probably dealing with an unmapped interface here
265 2
                        if ($parameter->isOptional()) {
266 1
                            $values[] = $parameter->getDefaultValue();
267
                        } else {
268 10
                            throw $e;
269
                        }
270
                    }
271
                } else {
272 1
                    $values[] = $parameter->getDefaultValue();
273
                }
274
            }
275
        }
276
277 11
        return $values;
278
    }
279
}
280