Container::remove()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
c 0
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Furious\Container;
6
7
use Closure;
8
use Furious\Container\Exception\DefinitionNotFoundException;
9
use Psr\Container\ContainerInterface;
10
use ReflectionClass;
11
use ReflectionException;
12
use ReflectionParameter;
13
use function array_key_exists;
14
use function class_exists;
15
16
final class Container implements ContainerInterface
17
{
18
    private array $values = [];
19
    private array $definitions;
20
21
    /**
22
     * Container constructor.
23
     * @param array $definitions
24
     */
25
    public function __construct(array $definitions = [])
26
    {
27
        $this->definitions = $definitions;
28
    }
29
30
    public function get($id)
31
    {
32
        if ($this->hasValue($id)) {
33
            return $this->values[$id];
34
        }
35
36
        if (!$this->hasDefinition($id)) {
37
            if ($this->classExists($id)) {
38
                return $this->values[$id] = $this->autowire($id);
39
            }
40
            throw new DefinitionNotFoundException($id);
41
        }
42
43
        $def = $this->definitions[$id];
44
        if ($def instanceof Closure) {
45
            return $this->values[$id] = $def($this);
46
        }
47
48
        return $this->values[$id] = $def;
49
    }
50
51
    public function set($id, $value): void
52
    {
53
        $this->put($id, $value);
54
    }
55
56
    public function put($id, $value): void
57
    {
58
        if ($this->hasValue($id)) {
59
            $this->remove($id);
60
        }
61
        $this->definitions[$id] = $value;
62
    }
63
64
    public function has($id): bool
65
    {
66
        return array_key_exists($id, $this->definitions) or $this->classExists($id);
67
    }
68
69
    private function remove($id): void
70
    {
71
        unset($this->values[$id]);
72
    }
73
74
    private function hasDefinition($id): bool
75
    {
76
        return array_key_exists($id, $this->definitions);
77
    }
78
79
    private function hasValue($id): bool
80
    {
81
        return array_key_exists($id, $this->values);
82
    }
83
84
    private function classExists($name): bool
85
    {
86
        return class_exists((string) $name);
87
    }
88
89
    /**
90
     * @param $id
91
     * @return object
92
     * @throws ReflectionException
93
     */
94
    private function autowire($id): object
95
    {
96
        $reflection = new ReflectionClass($id);
97
        $arguments = [];
98
99
        if (null !== ($constructor = $reflection->getConstructor())) {
100
            foreach ($constructor->getParameters() as $param) {
101
                $arguments[] = $this->getArgumentByParameter($param);
102
            }
103
        }
104
105
        return $reflection->newInstanceArgs($arguments);
106
    }
107
108
    /**
109
     * @param ReflectionParameter $param
110
     * @return array|mixed
111
     * @throws ReflectionException
112
     */
113
    private function getArgumentByParameter(ReflectionParameter $param)
114
    {
115
        if ($paramClass = $param->getClass()) {
116
            return $this->get($paramClass->getName());
117
        } elseif ($param->isArray()) {
118
            return [];
119
        } else {
120
            if (!$param->isDefaultValueAvailable()) {
121
                throw new DefinitionNotFoundException($param->getName());
122
            }
123
            return $param->getDefaultValue();
124
        }
125
    }
126
}