Passed
Branch main (61b4ec)
by Chema
02:26
created

Container::getDependencyResolver()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 9
ccs 6
cts 6
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Gacela\Container;
6
7
use Psr\Container\ContainerInterface;
8
9
use function is_callable;
10
use function is_object;
11
12
final class Container implements ContainerInterface
13
{
14
    private ?DependencyResolver $dependencyResolver = null;
15
16
    /** @var array<class-string,list<mixed>> */
17
    private array $cachedDependencies = [];
18
19
    /**
20
     * @param array<class-string, class-string|callable|object> $bindings
1 ignored issue
show
Documentation Bug introduced by
The doc comment array<class-string, class-string|callable|object> at position 2 could not be parsed: Unknown type name 'class-string' at position 2 in array<class-string, class-string|callable|object>.
Loading history...
21
     */
22 14
    public function __construct(
23
        private array $bindings = [],
24
    ) {
25 14
    }
26
27
    /**
28
     * @param class-string $className
29
     */
30 2
    public static function create(string $className): ?object
31
    {
32 2
        return (new self())->get($className);
33
    }
34
35 2
    public function has(string $id): bool
36
    {
37 2
        return is_object($this->get($id));
38
    }
39
40
    /**
41
     * @param class-string|string $id
42
     */
43 14
    public function get(string $id): ?object
44
    {
45 14
        if (isset($this->bindings[$id])) {
46 4
            $binding = $this->bindings[$id];
47 4
            if (is_callable($binding)) {
48
                /** @var mixed $binding */
49 2
                $binding = $binding();
50
            }
51 4
            if (is_object($binding)) {
52 2
                return $binding;
53
            }
54
55
            /** @var class-string $binding */
56 2
            if (class_exists($binding)) {
57 2
                return $this->instantiateClass($binding);
58
            }
59
        }
60
61 10
        if (class_exists($id)) {
62 8
            return $this->instantiateClass($id);
63
        }
64
65 2
        return null;
66
    }
67
68
    /**
69
     * @param class-string $class
70
     */
71 10
    private function instantiateClass(string $class): ?object
72
    {
73 10
        if (class_exists($class)) {
74 10
            if (!isset($this->cachedDependencies[$class])) {
75 10
                $this->cachedDependencies[$class] = $this
76 10
                    ->getDependencyResolver()
77 10
                    ->resolveDependencies($class);
78
            }
79
80
            /** @psalm-suppress MixedMethodCall */
81 10
            return new $class(...$this->cachedDependencies[$class]);
82
        }
83
84
        return null;
85
    }
86
87 10
    private function getDependencyResolver(): DependencyResolver
88
    {
89 10
        if ($this->dependencyResolver === null) {
90 10
            $this->dependencyResolver = new DependencyResolver(
91 10
                $this->bindings,
92 10
            );
93
        }
94
95 10
        return $this->dependencyResolver;
1 ignored issue
show
Bug Best Practice introduced by
The expression return $this->dependencyResolver could return the type null which is incompatible with the type-hinted return Gacela\Container\DependencyResolver. Consider adding an additional type-check to rule them out.
Loading history...
96
    }
97
}
98