Completed
Push — master ( 6411fa...6ee6e0 )
by Jesse
02:41
created

Container::typeMustCheckOut()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 4
nc 4
nop 3
dl 0
loc 6
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Stratadox\Di;
6
7
use Closure;
8
use Psr\Container\ContainerInterface as PsrContainerInterface;
9
use Throwable;
10
11
final class Container implements ContainerInterface, PsrContainerInterface
12
{
13
    protected $remember = [];
14
    protected $factoryFor = [];
15
    protected $mustReload = [];
16
    protected $isCurrentlyResolving = [];
17
18
    public function get($theService)
19
    {
20
        $this->mustKnowAbout($theService);
21
22
        if ($this->hasNotYetLoaded($theService) or $this->mustReload[$theService]) {
23
            $this->remember[$theService] = $this->load($theService);
24
        }
25
26
        return $this->remember[$theService];
27
    }
28
29
    public function has($theService) : bool
30
    {
31
        return isset($this->factoryFor[$theService]);
32
    }
33
34
    public function set(
35
        string $theService,
36
        Closure $producingTheService,
37
        bool $cache = true
38
    ) : void
39
    {
40
        $this->remember[$theService] = null;
41
        $this->factoryFor[$theService] = $producingTheService;
42
        $this->mustReload[$theService] = !$cache;
43
    }
44
45
    public function forget(string $theService) : void
46
    {
47
        unset($this->remember[$theService]);
48
        unset($this->factoryFor[$theService]);
49
        unset($this->mustReload[$theService]);
50
    }
51
52
    /** @throws InvalidServiceDefinition */
53
    private function load(string $theService)
54
    {
55
        if (isset($this->isCurrentlyResolving[$theService])) {
56
            throw DependenciesCannotBeCircular::loopDetectedIn($theService);
57
        }
58
        $this->isCurrentlyResolving[$theService] = true;
59
60
        $makeTheService = $this->factoryFor[$theService];
61
        try {
62
            return $makeTheService();
63
        } catch (Throwable $encounteredException) {
64
            throw InvalidFactory::threwException($theService, $encounteredException);
65
        } finally {
66
            unset($this->isCurrentlyResolving[$theService]);
67
        }
68
    }
69
70
    private function hasNotYetLoaded(string $theService) : bool
71
    {
72
        return !isset($this->remember[$theService]);
73
    }
74
75
    /** @throws ServiceNotFound */
76
    private function mustKnowAbout(string $theService) : void
77
    {
78
        if ($this->has($theService)) return;
79
        throw ServiceNotFound::noServiceNamed($theService);
80
    }
81
}
82